@@ -10,9 +10,7 @@ import {
1010import { Input } from "@/browser/components/Input/Input" ;
1111import { Switch } from "@/browser/components/Switch/Switch" ;
1212import { usePersistedState } from "@/browser/hooks/usePersistedState" ;
13- import { useExperimentValue } from "@/browser/hooks/useExperiments" ;
1413import { useAPI } from "@/browser/contexts/API" ;
15- import { EXPERIMENT_IDS } from "@/common/constants/experiments" ;
1614import { CUSTOM_EVENTS , createCustomEvent } from "@/common/constants/events" ;
1715import {
1816 EDITOR_CONFIG_KEY ,
@@ -41,7 +39,6 @@ import {
4139 isWorktreeArchiveBehavior ,
4240 type WorktreeArchiveBehavior ,
4341} from "@/common/config/worktreeArchiveBehavior" ;
44- import { HEARTBEAT_DEFAULT_MESSAGE_BODY } from "@/constants/heartbeat" ;
4542
4643// Guard against corrupted/old persisted settings (e.g. from a downgraded build).
4744const ALLOWED_EDITOR_TYPES : ReadonlySet < EditorType > = new Set ( [
@@ -163,7 +160,6 @@ const isBrowserMode = typeof window !== "undefined" && !window.api;
163160export function GeneralSection ( ) {
164161 const { themePreference, setTheme } = useTheme ( ) ;
165162 const { api } = useAPI ( ) ;
166- const workspaceHeartbeatsEnabled = useExperimentValue ( EXPERIMENT_IDS . WORKSPACE_HEARTBEATS ) ;
167163 const [ launchBehavior , setLaunchBehavior ] = usePersistedState < LaunchBehavior > (
168164 LAUNCH_BEHAVIOR_KEY ,
169165 "dashboard"
@@ -207,23 +203,18 @@ export function GeneralSection() {
207203 ) ;
208204 const [ archiveSettingsLoaded , setArchiveSettingsLoaded ] = useState ( false ) ;
209205 const [ llmDebugLogs , setLlmDebugLogs ] = useState ( false ) ;
210- const [ heartbeatDefaultPrompt , setHeartbeatDefaultPrompt ] = useState ( "" ) ;
211- const [ heartbeatDefaultPromptLoaded , setHeartbeatDefaultPromptLoaded ] = useState ( false ) ;
212- const [ heartbeatDefaultPromptLoadedOk , setHeartbeatDefaultPromptLoadedOk ] = useState ( false ) ;
213206 const archiveBehaviorLoadNonceRef = useRef ( 0 ) ;
214207 const archiveBehaviorRef = useRef < CoderWorkspaceArchiveBehavior > ( DEFAULT_CODER_ARCHIVE_BEHAVIOR ) ;
215208 const worktreeArchiveBehaviorRef = useRef < WorktreeArchiveBehavior > (
216209 DEFAULT_WORKTREE_ARCHIVE_BEHAVIOR
217210 ) ;
218211
219212 const llmDebugLogsLoadNonceRef = useRef ( 0 ) ;
220- const heartbeatDefaultPromptLoadNonceRef = useRef ( 0 ) ;
221213
222214 // updateCoderPrefs writes config.json on the backend. Serialize (and coalesce) updates so rapid
223215 // selections can't race and persist a stale value via out-of-order writes.
224216 const archiveBehaviorUpdateChainRef = useRef < Promise < void > > ( Promise . resolve ( ) ) ;
225217 const llmDebugLogsUpdateChainRef = useRef < Promise < void > > ( Promise . resolve ( ) ) ;
226- const heartbeatDefaultPromptUpdateChainRef = useRef < Promise < void > > ( Promise . resolve ( ) ) ;
227218 const archiveBehaviorPendingUpdateRef = useRef < CoderWorkspaceArchiveBehavior | undefined > (
228219 undefined
229220 ) ;
@@ -237,11 +228,8 @@ export function GeneralSection() {
237228 }
238229
239230 setArchiveSettingsLoaded ( false ) ;
240- setHeartbeatDefaultPromptLoaded ( false ) ;
241- setHeartbeatDefaultPromptLoadedOk ( false ) ;
242231 const archiveBehaviorNonce = ++ archiveBehaviorLoadNonceRef . current ;
243232 const llmDebugLogsNonce = ++ llmDebugLogsLoadNonceRef . current ;
244- const heartbeatDefaultPromptNonce = ++ heartbeatDefaultPromptLoadNonceRef . current ;
245233
246234 void api . config
247235 . getConfig ( )
@@ -268,25 +256,13 @@ export function GeneralSection() {
268256 if ( llmDebugLogsNonce === llmDebugLogsLoadNonceRef . current ) {
269257 setLlmDebugLogs ( cfg . llmDebugLogs === true ) ;
270258 }
271-
272- if ( heartbeatDefaultPromptNonce === heartbeatDefaultPromptLoadNonceRef . current ) {
273- setHeartbeatDefaultPrompt ( cfg . heartbeatDefaultPrompt ?? "" ) ;
274- setHeartbeatDefaultPromptLoaded ( true ) ;
275- setHeartbeatDefaultPromptLoadedOk ( true ) ;
276- }
277259 } )
278260 . catch ( ( ) => {
279261 if ( archiveBehaviorNonce === archiveBehaviorLoadNonceRef . current ) {
280262 // Fall back to the safe defaults already in state so the controls can recover after a
281263 // config read failure and the next user change can persist a fresh value.
282264 setArchiveSettingsLoaded ( true ) ;
283265 }
284-
285- if ( heartbeatDefaultPromptNonce === heartbeatDefaultPromptLoadNonceRef . current ) {
286- // Keep the field editable after load failures, but avoid clearing an existing saved
287- // prompt unless the user has actively typed a replacement in this session.
288- setHeartbeatDefaultPromptLoaded ( true ) ;
289- }
290266 } ) ;
291267 } , [ api ] ) ;
292268
@@ -391,35 +367,6 @@ export function GeneralSection() {
391367 } ) ;
392368 } ;
393369
394- const handleHeartbeatDefaultPromptBlur = useCallback ( ( ) => {
395- if ( ! heartbeatDefaultPromptLoaded || ! api ?. config ?. updateHeartbeatDefaultPrompt ) {
396- return ;
397- }
398-
399- const trimmedDefaultPrompt = heartbeatDefaultPrompt . trim ( ) ;
400- if ( ! heartbeatDefaultPromptLoadedOk && ! trimmedDefaultPrompt ) {
401- return ;
402- }
403-
404- setHeartbeatDefaultPrompt ( trimmedDefaultPrompt ) ;
405-
406- heartbeatDefaultPromptUpdateChainRef . current = heartbeatDefaultPromptUpdateChainRef . current
407- . catch ( ( ) => {
408- // Best-effort only.
409- } )
410- . then ( ( ) =>
411- api . config . updateHeartbeatDefaultPrompt ( {
412- defaultPrompt : trimmedDefaultPrompt || null ,
413- } )
414- )
415- . then ( ( ) => {
416- setHeartbeatDefaultPromptLoadedOk ( true ) ;
417- } )
418- . catch ( ( ) => {
419- // Best-effort persistence.
420- } ) ;
421- } , [ api , heartbeatDefaultPrompt , heartbeatDefaultPromptLoaded , heartbeatDefaultPromptLoadedOk ] ) ;
422-
423370 // Load SSH host from server on mount (browser mode only)
424371 useEffect ( ( ) => {
425372 if ( isBrowserMode && api ) {
@@ -612,30 +559,6 @@ export function GeneralSection() {
612559 aria-label = "Toggle API Debug Logs"
613560 />
614561 </ div >
615- { workspaceHeartbeatsEnabled ? (
616- < div className = "py-3" >
617- < label htmlFor = "heartbeat-default-prompt" className = "block" >
618- < div className = "text-foreground text-sm" > Default heartbeat prompt</ div >
619- < div className = "text-muted mt-0.5 text-xs" >
620- Used for workspace heartbeats when a workspace does not set its own message.
621- </ div >
622- </ label >
623- < textarea
624- id = "heartbeat-default-prompt"
625- rows = { 4 }
626- value = { heartbeatDefaultPrompt }
627- onChange = { ( event : React . ChangeEvent < HTMLTextAreaElement > ) => {
628- heartbeatDefaultPromptLoadNonceRef . current ++ ;
629- setHeartbeatDefaultPromptLoaded ( true ) ;
630- setHeartbeatDefaultPrompt ( event . target . value ) ;
631- } }
632- onBlur = { handleHeartbeatDefaultPromptBlur }
633- className = "border-border-medium bg-background-secondary text-foreground focus:border-accent focus:ring-accent mt-3 min-h-[120px] w-full resize-y rounded-md border p-3 text-sm leading-relaxed focus:ring-1 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
634- placeholder = { HEARTBEAT_DEFAULT_MESSAGE_BODY }
635- aria-label = "Default heartbeat prompt"
636- />
637- </ div >
638- ) : null }
639562 </ div >
640563 </ div >
641564
0 commit comments