diff --git a/package-lock.json b/package-lock.json
index 0dae4ee453..9d6304649e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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"
diff --git a/package.json b/package.json
index fc5d55130c..64c5ce2b5e 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/core/Cline.ts b/src/core/Cline.ts
index 1a5c058db9..9066a7fbf7 100644
--- a/src/core/Cline.ts
+++ b/src/core/Cline.ts
@@ -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 {
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index e0d8121763..77e3a6691c 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -387,9 +387,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
-
+
Cline
@@ -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,
}
}
diff --git a/src/services/telemetry/TelemetryService.ts b/src/services/telemetry/TelemetryService.ts
index 19dcf0829b..b4fbd063c8 100644
--- a/src/services/telemetry/TelemetryService.ts
+++ b/src/services/telemetry/TelemetryService.ts
@@ -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()
diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts
index bcad63b788..8924e7adad 100644
--- a/src/shared/ExtensionMessage.ts
+++ b/src/shared/ExtensionMessage.ts
@@ -95,6 +95,7 @@ export interface ExtensionState {
}
mcpMarketplaceEnabled?: boolean
telemetrySetting: TelemetrySetting
+ vscMachineId: string
}
export interface ClineMessage {
diff --git a/webview-ui/package-lock.json b/webview-ui/package-lock.json
index 0a5b09fee8..b045f714fb 100644
--- a/webview-ui/package-lock.json
+++ b/webview-ui/package-lock.json
@@ -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",
diff --git a/webview-ui/package.json b/webview-ui/package.json
index e0d70cf37f..82055bb9db 100644
--- a/webview-ui/package.json
+++ b/webview-ui/package.json
@@ -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",
diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx
index 0043ef330b..a21e68b3db 100644
--- a/webview-ui/src/App.tsx
+++ b/webview-ui/src/App.tsx
@@ -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)
diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx
index afe84601ed..7a74d2c178 100644
--- a/webview-ui/src/components/chat/ChatView.tsx
+++ b/webview-ui/src/components/chat/ChatView.tsx
@@ -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" && }
{showAnnouncement && }
+
What can I do for you?
diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx
index f3d0619183..aba1836c54 100644
--- a/webview-ui/src/context/ExtensionStateContext.tsx
+++ b/webview-ui/src/context/ExtensionStateContext.tsx
@@ -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)
diff --git a/webview-ui/src/main.tsx b/webview-ui/src/main.tsx
index b0094ef51c..a6cefc5bd2 100644
--- a/webview-ui/src/main.tsx
+++ b/webview-ui/src/main.tsx
@@ -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(
-
+
+
+
,
)