add optional telemetry (#1939)

* add optional telemetry

* move capture

* add changeset

* implement suggestions
This commit is contained in:
Trevor Hudson 2025-02-25 16:43:15 -08:00
parent 5d8172a25f
commit e5d616b0bf
12 changed files with 122 additions and 14 deletions

12
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "claude-dev",
"version": "3.4.8",
"version": "3.4.9",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claude-dev",
"version": "3.4.8",
"version": "3.4.9",
"license": "Apache-2.0",
"dependencies": {
"@anthropic-ai/bedrock-sdk": "^0.10.2",
@ -41,7 +41,7 @@
"os-name": "^6.0.0",
"p-wait-for": "^5.0.2",
"pdf-parse": "^1.1.1",
"posthog-node": "^4.7.0",
"posthog-node": "^4.8.1",
"puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0",
"serialize-error": "^11.0.3",
@ -11247,9 +11247,9 @@
}
},
"node_modules/posthog-node": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.7.0.tgz",
"integrity": "sha512-RgdUKSW8MfMOkjUa8cYVqWndNjPePNuuxlGbrZC6z1WRBsVc6TdGl8caidmC10RW8mu/BOfmrGbP4cRTo2jARg==",
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.8.1.tgz",
"integrity": "sha512-ApMEC1+DbctP/88+VhaCl8SRKpIoReibMf7Mb3rxw3yMthr1rKaM4opbHdZJ0buLhwS5zX8B2ckqLjpwpSjRPg==",
"license": "MIT",
"dependencies": {
"axios": "^1.7.4"

View file

@ -294,7 +294,7 @@
"os-name": "^6.0.0",
"p-wait-for": "^5.0.2",
"pdf-parse": "^1.1.1",
"posthog-node": "^4.7.0",
"posthog-node": "^4.8.1",
"puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0",
"serialize-error": "^11.0.3",

View file

@ -60,6 +60,7 @@ import { addUserInstructions, SYSTEM_PROMPT } from "./prompts/system"
import { getNextTruncationRange, getTruncatedMessages } from "./sliding-window"
import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider"
import { DEFAULT_LANGUAGE_SETTINGS, getLanguageKey, LanguageDisplay, LanguageKey } from "../shared/Languages"
import { telemetryService } from "../services/telemetry/TelemetryService"
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? path.join(os.homedir(), "Desktop") // may or may not exist but fs checking existence would immediately ask for permission which would be bad UX, need to come up with a better solution
@ -153,6 +154,16 @@ export class Cline {
} else {
throw new Error("Either historyItem or task/images must be provided")
}
// capture start of thread with the state at the beginning
telemetryService.capture({
event: "cline created",
properties: {
taskId: this.taskId,
isHistory: !!historyItem,
chatMode: this.chatSettings.mode,
hasImages: !!images,
},
})
}
updateBrowserSettings(browserSettings: BrowserSettings) {
@ -3284,6 +3295,14 @@ export class Cline {
this.consecutiveMistakeCount++
}
telemetryService.capture({
event: "message sent",
properties: {
taskId: this.taskId,
chatMode: this.chatSettings.mode,
},
})
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent)
didEndLoop = recDidEndLoop
} else {

View file

@ -387,9 +387,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${webview.cspSource}; style-src ${webview.cspSource} 'unsafe-inline'; img-src ${webview.cspSource} https: data:; script-src 'nonce-${nonce}';">
<link rel="stylesheet" type="text/css" href="${stylesUri}">
<link href="${codiconsUri}" rel="stylesheet" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; connect-src https://*.posthog.com; font-src ${webview.cspSource}; style-src ${webview.cspSource} 'unsafe-inline'; img-src ${webview.cspSource} https: data:; script-src 'nonce-${nonce}' https://*.posthog.com;">
<title>Cline</title>
</head>
<body>
@ -1745,6 +1745,7 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont
userInfo,
mcpMarketplaceEnabled,
telemetrySetting,
vscMachineId: vscode.env.machineId,
}
}

View file

@ -26,9 +26,10 @@ class PostHogClient {
this.telemetryEnabled = didUserOptIn
}
// Update PostHog client state based on telemetry preference
// Update PostHog client state based on telemetry preference and use machineId to tie it to the webview
if (this.telemetryEnabled) {
this.client.optIn()
this.client.identify({ distinctId: this.distinctId })
// console.log("Telemetry enabled")
} else {
this.client.optOut()

View file

@ -95,6 +95,7 @@ export interface ExtensionState {
}
mcpMarketplaceEnabled?: boolean
telemetrySetting: TelemetrySetting
vscMachineId: string
}
export interface ClineMessage {

View file

@ -17,6 +17,7 @@
"fuse.js": "^7.0.0",
"fzf": "^0.5.2",
"mermaid": "^11.4.1",
"posthog-js": "^1.224.0",
"pretty-bytes": "^6.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@ -1468,6 +1469,16 @@
"win32"
]
},
"node_modules/@rrweb/types": {
"version": "2.0.0-alpha.17",
"resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.17.tgz",
"integrity": "sha512-AfDTVUuCyCaIG0lTSqYtrZqJX39ZEYzs4fYKnexhQ+id+kbZIpIJtaut5cto6dWZbB3SEe4fW0o90Po3LvTmfg==",
"license": "MIT",
"peer": true,
"dependencies": {
"rrweb-snapshot": "^2.0.0-alpha.17"
}
},
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@ -3024,6 +3035,17 @@
"toggle-selection": "^1.0.6"
}
},
"node_modules/core-js": {
"version": "3.40.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz",
"integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==",
"hasInstallScript": true,
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cose-base": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz",
@ -4201,6 +4223,12 @@
"reusify": "^1.0.4"
}
},
"node_modules/fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==",
"license": "MIT"
},
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@ -5799,7 +5827,6 @@
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -5830,6 +5857,37 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"license": "MIT"
},
"node_modules/posthog-js": {
"version": "1.224.0",
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.224.0.tgz",
"integrity": "sha512-JT1XQQeYs0CKb4lU2vujmeLTDLWc61I5lT7d6oG/H/cnCpXAqBi5rMuCFFeotHeMy3hqJ/Tpu3eAPFE2p5ErHA==",
"license": "MIT",
"dependencies": {
"core-js": "^3.38.1",
"fflate": "^0.4.8",
"preact": "^10.19.3",
"web-vitals": "^4.2.0"
},
"peerDependencies": {
"@rrweb/types": "2.0.0-alpha.17"
}
},
"node_modules/posthog-js/node_modules/web-vitals": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
"license": "Apache-2.0"
},
"node_modules/preact": {
"version": "10.26.2",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.26.2.tgz",
"integrity": "sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -6214,6 +6272,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/rrweb-snapshot": {
"version": "2.0.0-alpha.18",
"resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-2.0.0-alpha.18.tgz",
"integrity": "sha512-hBHZL/NfgQX6wO1D9mpwqFu1NJPpim+moIcKhFEjVTZVRUfCln+LOugRc4teVTCISYHN8Cw5e2iNTWCSm+SkoA==",
"license": "MIT",
"peer": true,
"dependencies": {
"postcss": "^8.4.38"
}
},
"node_modules/rtl-css-js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",

View file

@ -21,6 +21,7 @@
"fuse.js": "^7.0.0",
"fzf": "^0.5.2",
"mermaid": "^11.4.1",
"posthog-js": "^1.224.0",
"pretty-bytes": "^6.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",

View file

@ -9,9 +9,10 @@ import AccountView from "./components/account/AccountView"
import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext"
import { vscode } from "./utils/vscode"
import McpView from "./components/mcp/McpView"
import posthog from "posthog-js"
const AppContent = () => {
const { didHydrateState, showWelcome, shouldShowAnnouncement } = useExtensionState()
const { didHydrateState, showWelcome, shouldShowAnnouncement, telemetrySetting, vscMachineId } = useExtensionState()
const [showSettings, setShowSettings] = useState(false)
const [showHistory, setShowHistory] = useState(false)
const [showMcp, setShowMcp] = useState(false)
@ -60,6 +61,15 @@ const AppContent = () => {
useEvent("message", handleMessage)
useEffect(() => {
if (telemetrySetting === "enabled") {
posthog.identify(vscMachineId)
posthog.opt_in_capturing()
} else {
posthog.opt_out_capturing()
}
}, [telemetrySetting, vscMachineId])
useEffect(() => {
if (shouldShowAnnouncement) {
setShowAnnouncement(true)

View file

@ -1,4 +1,4 @@
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
import debounce from "debounce"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useDeepCompareEffect, useEvent, useMount } from "react-use"
@ -793,6 +793,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
{telemetrySetting === "unset" && <TelemetryBanner />}
{showAnnouncement && <Announcement version={version} hideAnnouncement={hideAnnouncement} />}
<div style={{ padding: "0 20px", flexShrink: 0 }}>
<h2>What can I do for you?</h2>
<p>

View file

@ -42,6 +42,7 @@ export const ExtensionStateContextProvider: React.FC<{
isLoggedIn: false,
platform: DEFAULT_PLATFORM,
telemetrySetting: "unset",
vscMachineId: "",
})
const [didHydrateState, setDidHydrateState] = useState(false)
const [showWelcome, setShowWelcome] = useState(false)

View file

@ -1,12 +1,17 @@
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import { PostHogProvider } from "posthog-js/react"
import "./index.css"
import App from "./App.tsx"
import "../../node_modules/@vscode/codicons/dist/codicon.css"
const apiKey = "phc_5WnLHpYyC30Bsb7VSJ6DzcPXZ34JSF08DJLyM7svZ15"
const apiHost = "https://us.i.posthog.com"
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
<PostHogProvider apiKey={apiKey} options={{ api_host: apiHost }}>
<App />
</PostHogProvider>
</StrictMode>,
)