Skip to content

Commit 1c7d33a

Browse files
celestial-vaultElephant Lumps
andauthored
Add remote config webview. (RooCodeInc#3243)
* added posthog remote config * changeset * add feature flags constant * move init outside function to keep from potentially re-running --------- Co-authored-by: Elephant Lumps <[email protected]>
1 parent eb6e481 commit 1c7d33a

File tree

7 files changed

+71
-28
lines changed

7 files changed

+71
-28
lines changed

.changeset/real-cobras-rule.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": minor
3+
---
4+
5+
Add remote config with posthog allowing for disabling new features until they're reading, making for a better developer experience.

src/services/telemetry/TelemetryService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { version as extensionVersion } from "../../../package.json"
44

55
import type { TaskFeedbackType } from "@shared/WebviewMessage"
66
import type { BrowserSettings } from "@shared/BrowserSettings"
7+
import { posthogConfig } from "@/shared/services/config/posthog-config"
78

89
/**
910
* PostHogClient handles telemetry event tracking for the Cline extension
@@ -93,8 +94,8 @@ class PostHogClient {
9394
* Initializes PostHog client with configuration
9495
*/
9596
private constructor() {
96-
this.client = new PostHog("phc_qfOAGxZw2TL5O8p9KYd9ak3bPBFzfjC8fy5L6jNWY7K", {
97-
host: "https://us.i.posthog.com",
97+
this.client = new PostHog(posthogConfig.apiKey, {
98+
host: posthogConfig.host,
9899
enableExceptionAutocapture: false,
99100
})
100101
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Public PostHog key (safe for open source)
2+
export const posthogConfig = {
3+
apiKey: "phc_qfOAGxZw2TL5O8p9KYd9ak3bPBFzfjC8fy5L6jNWY7K",
4+
host: "https://us.i.posthog.com",
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const FEATURE_FLAGS = {
2+
CUSTOM_INSTRUCTIONS: "custom-instructions",
3+
// Further flags here
4+
} as const
5+
6+
export type FeatureFlag = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

webview-ui/src/Providers.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,22 @@ import type { ReactNode } from "react"
33
import { ExtensionStateContextProvider } from "./context/ExtensionStateContext"
44
import { FirebaseAuthProvider } from "./context/FirebaseAuthContext"
55
import { HeroUIProvider } from "@heroui/react"
6+
import { PostHogProvider } from "posthog-js/react"
7+
import { posthogConfig } from "@shared/services/config/posthog-config"
8+
import posthog from "posthog-js"
9+
10+
posthog.init(posthogConfig.apiKey, {
11+
api_host: posthogConfig.host,
12+
})
613

714
export function Providers({ children }: { children: ReactNode }) {
815
return (
916
<ExtensionStateContextProvider>
10-
<FirebaseAuthProvider>
11-
<HeroUIProvider>{children}</HeroUIProvider>
12-
</FirebaseAuthProvider>
17+
<PostHogProvider client={posthog}>
18+
<FirebaseAuthProvider>
19+
<HeroUIProvider>{children}</HeroUIProvider>
20+
</FirebaseAuthProvider>
21+
</PostHogProvider>
1322
</ExtensionStateContextProvider>
1423
)
1524
}

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { useEvent } from "react-use"
1010
import { ExtensionMessage } from "@shared/ExtensionMessage"
1111
import BrowserSettingsSection from "./BrowserSettingsSection"
1212
import TerminalSettingsSection from "./TerminalSettingsSection"
13-
13+
import { useFeatureFlag } from "@/hooks/useFeatureFlag"
14+
import { FEATURE_FLAGS } from "@shared/services/feature-flags/feature-flags"
1415
const { IS_DEV } = process.env
1516

1617
type SettingsViewProps = {
@@ -82,16 +83,16 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
8283

8384
// validate as soon as the component is mounted
8485
/*
85-
useEffect will use stale values of variables if they are not included in the dependency array.
86-
so trying to use useEffect with a dependency array of only one value for example will use any
87-
other variables' old values. In most cases you don't want this, and should opt to use react-use
88-
hooks.
86+
useEffect will use stale values of variables if they are not included in the dependency array.
87+
so trying to use useEffect with a dependency array of only one value for example will use any
88+
other variables' old values. In most cases you don't want this, and should opt to use react-use
89+
hooks.
8990
90-
// uses someVar and anotherVar
91-
// eslint-disable-next-line react-hooks/exhaustive-deps
92-
}, [someVar])
91+
// uses someVar and anotherVar
92+
// eslint-disable-next-line react-hooks/exhaustive-deps
93+
}, [someVar])
9394
If we only want to run code once on mount we can use react-use's useEffectOnce or useMount
94-
*/
95+
*/
9596

9697
const handleMessage = useCallback(
9798
(event: MessageEvent) => {
@@ -145,6 +146,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
145146
handleSubmit(true)
146147
}
147148

149+
const showCustomInstructions = useFeatureFlag(FEATURE_FLAGS.CUSTOM_INSTRUCTIONS)
150+
148151
return (
149152
<div className="fixed top-0 left-0 right-0 bottom-0 pt-[10px] pr-0 pb-0 pl-5 flex flex-col overflow-hidden">
150153
<div className="flex justify-between items-center mb-[13px] pr-[17px]">
@@ -183,20 +186,24 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
183186
/>
184187
)}
185188

186-
<div className="mb-[5px]">
187-
<VSCodeTextArea
188-
value={customInstructions ?? ""}
189-
className="w-full"
190-
resize="vertical"
191-
rows={4}
192-
placeholder={'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'}
193-
onInput={(e: any) => setCustomInstructions(e.target?.value ?? "")}>
194-
<span className="font-medium">Custom Instructions</span>
195-
</VSCodeTextArea>
196-
<p className="text-xs mt-[5px] text-[var(--vscode-descriptionForeground)]">
197-
These instructions are added to the end of the system prompt sent with every request.
198-
</p>
199-
</div>
189+
{showCustomInstructions && (
190+
<div className="mb-[5px]">
191+
<VSCodeTextArea
192+
value={customInstructions ?? ""}
193+
className="w-full"
194+
resize="vertical"
195+
rows={4}
196+
placeholder={
197+
'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'
198+
}
199+
onInput={(e: any) => setCustomInstructions(e.target?.value ?? "")}>
200+
<span className="font-medium">Custom Instructions</span>
201+
</VSCodeTextArea>
202+
<p className="text-xs mt-[5px] text-[var(--vscode-descriptionForeground)]">
203+
These instructions are added to the end of the system prompt sent with every request.
204+
</p>
205+
</div>
206+
)}
200207

201208
<div className="mb-[5px]">
202209
<VSCodeCheckbox
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useFeatureFlagPayload } from "posthog-js/react"
2+
3+
export const useFeatureFlag = (flagName: string): boolean => {
4+
const payload = useFeatureFlagPayload(flagName) as { enabled: boolean }
5+
if (payload && payload.enabled) {
6+
return payload.enabled
7+
}
8+
console.warn(`Feature flag ${flagName} not found or missing enabled property.`)
9+
return false
10+
}

0 commit comments

Comments
 (0)