@@ -12,6 +12,7 @@ import * as Effect from "effect/Effect";
1212import * as Duration from "effect/Duration" ;
1313import * as FileSystem from "effect/FileSystem" ;
1414import * as Layer from "effect/Layer" ;
15+ import * as Path from "effect/Path" ;
1516import * as PlatformError from "effect/PlatformError" ;
1617import * as Schema from "effect/Schema" ;
1718import * as ServerSecretStore from "./auth/ServerSecretStore.ts" ;
@@ -486,6 +487,7 @@ it.layer(NodeServices.layer)("server settings", (it) => {
486487 const fileSystem = yield * FileSystem . FileSystem ;
487488 const next = yield * serverSettings . updateSettings ( {
488489 addProjectBaseDirectory : "~/Development" ,
490+ automaticGitFetchInterval : Duration . seconds ( 10 ) ,
489491 observability : {
490492 otlpTracesUrl : "http://localhost:4318/v1/traces" ,
491493 otlpMetricsUrl : "http://localhost:4318/v1/metrics" ,
@@ -499,7 +501,8 @@ it.layer(NodeServices.layer)("server settings", (it) => {
499501 serverPassword : "secret-password" ,
500502 } ,
501503 } ,
502- automaticGitFetchInterval : Duration . seconds ( 10 ) ,
504+ telemetryEnabled : true ,
505+ telemetryPreferenceSet : true ,
503506 } ) ;
504507
505508 assert . equal ( next . providers . codex . binaryPath , "/opt/homebrew/bin/codex" ) ;
@@ -508,6 +511,7 @@ it.layer(NodeServices.layer)("server settings", (it) => {
508511 // @effect -diagnostics-next-line preferSchemaOverJson:off
509512 assert . deepEqual ( JSON . parse ( raw ) , {
510513 addProjectBaseDirectory : "~/Development" ,
514+ automaticGitFetchInterval : 10_000 ,
511515 observability : {
512516 otlpTracesUrl : "http://localhost:4318/v1/traces" ,
513517 otlpMetricsUrl : "http://localhost:4318/v1/metrics" ,
@@ -521,11 +525,117 @@ it.layer(NodeServices.layer)("server settings", (it) => {
521525 serverPassword : "secret-password" ,
522526 } ,
523527 } ,
524- automaticGitFetchInterval : 10_000 ,
528+ telemetryEnabled : true ,
529+ telemetryPreferenceSet : true ,
525530 } ) ;
526531 } ) . pipe ( Effect . provide ( makeServerSettingsLayer ( ) ) ) ,
527532 ) ;
528533
534+ it . effect ( "persists explicit telemetry opt-out marker" , ( ) =>
535+ Effect . gen ( function * ( ) {
536+ const serverSettings = yield * ServerSettingsModule . ServerSettingsService ;
537+ const serverConfig = yield * ServerConfig . ServerConfig ;
538+ const fileSystem = yield * FileSystem . FileSystem ;
539+
540+ yield * serverSettings . updateSettings ( {
541+ telemetryEnabled : false ,
542+ } ) ;
543+
544+ const raw = yield * fileSystem . readFileString ( serverConfig . settingsPath ) ;
545+ // @effect -diagnostics-next-line preferSchemaOverJson:off
546+ assert . deepEqual ( JSON . parse ( raw ) , {
547+ telemetryPreferenceSet : true ,
548+ } ) ;
549+ } ) . pipe ( Effect . provide ( makeServerSettingsLayer ( ) ) ) ,
550+ ) ;
551+
552+ it . effect ( "loads persisted telemetryEnabled as an explicit preference" , ( ) =>
553+ Effect . gen ( function * ( ) {
554+ const fileSystem = yield * FileSystem . FileSystem ;
555+ const path = yield * Path . Path ;
556+ const baseDir = yield * fileSystem . makeTempDirectoryScoped ( {
557+ prefix : "t3code-server-settings-telemetry-" ,
558+ } ) ;
559+ const settingsPath = path . join ( baseDir , "userdata" , "settings.json" ) ;
560+ yield * fileSystem . makeDirectory ( path . dirname ( settingsPath ) , { recursive : true } ) ;
561+ yield * fileSystem . writeFileString ( settingsPath , '{ "telemetryEnabled": false }\n' ) ;
562+
563+ const layer = ServerSettingsModule . layer . pipe (
564+ Layer . provide ( ServerSecretStore . layer ) ,
565+ Layer . provideMerge ( ServerConfig . layerTest ( process . cwd ( ) , baseDir ) ) ,
566+ ) ;
567+ const settings = yield * Effect . gen ( function * ( ) {
568+ const serverSettings = yield * ServerSettingsModule . ServerSettingsService ;
569+ yield * serverSettings . start ;
570+ return yield * serverSettings . getSettings ;
571+ } ) . pipe ( Effect . provide ( layer ) ) ;
572+
573+ assert . deepInclude ( settings , {
574+ telemetryEnabled : false ,
575+ telemetryPreferenceSet : true ,
576+ } ) ;
577+ } ) ,
578+ ) ;
579+
580+ it . effect ( "loads malformed persisted telemetryEnabled as an explicit preference" , ( ) =>
581+ Effect . gen ( function * ( ) {
582+ const fileSystem = yield * FileSystem . FileSystem ;
583+ const path = yield * Path . Path ;
584+ const baseDir = yield * fileSystem . makeTempDirectoryScoped ( {
585+ prefix : "t3code-server-settings-telemetry-malformed-" ,
586+ } ) ;
587+ const settingsPath = path . join ( baseDir , "userdata" , "settings.json" ) ;
588+ yield * fileSystem . makeDirectory ( path . dirname ( settingsPath ) , { recursive : true } ) ;
589+ yield * fileSystem . writeFileString ( settingsPath , '{ "telemetryEnabled": "false" }\n' ) ;
590+
591+ const layer = ServerSettingsModule . layer . pipe (
592+ Layer . provide ( ServerSecretStore . layer ) ,
593+ Layer . provideMerge ( ServerConfig . layerTest ( process . cwd ( ) , baseDir ) ) ,
594+ ) ;
595+ const settings = yield * Effect . gen ( function * ( ) {
596+ const serverSettings = yield * ServerSettingsModule . ServerSettingsService ;
597+ yield * serverSettings . start ;
598+ return yield * serverSettings . getSettings ;
599+ } ) . pipe ( Effect . provide ( layer ) ) ;
600+
601+ assert . deepInclude ( settings , {
602+ telemetryEnabled : false ,
603+ telemetryPreferenceSet : true ,
604+ } ) ;
605+ } ) ,
606+ ) ;
607+
608+ it . effect ( "loads persisted telemetry opt-in from schema-invalid settings" , ( ) =>
609+ Effect . gen ( function * ( ) {
610+ const fileSystem = yield * FileSystem . FileSystem ;
611+ const path = yield * Path . Path ;
612+ const baseDir = yield * fileSystem . makeTempDirectoryScoped ( {
613+ prefix : "t3code-server-settings-telemetry-invalid-opt-in-" ,
614+ } ) ;
615+ const settingsPath = path . join ( baseDir , "userdata" , "settings.json" ) ;
616+ yield * fileSystem . makeDirectory ( path . dirname ( settingsPath ) , { recursive : true } ) ;
617+ yield * fileSystem . writeFileString (
618+ settingsPath ,
619+ '{ "telemetryEnabled": true, "providers": null }\n' ,
620+ ) ;
621+
622+ const layer = ServerSettingsModule . layer . pipe (
623+ Layer . provide ( ServerSecretStore . layer ) ,
624+ Layer . provideMerge ( ServerConfig . layerTest ( process . cwd ( ) , baseDir ) ) ,
625+ ) ;
626+ const settings = yield * Effect . gen ( function * ( ) {
627+ const serverSettings = yield * ServerSettingsModule . ServerSettingsService ;
628+ yield * serverSettings . start ;
629+ return yield * serverSettings . getSettings ;
630+ } ) . pipe ( Effect . provide ( layer ) ) ;
631+
632+ assert . deepInclude ( settings , {
633+ telemetryEnabled : true ,
634+ telemetryPreferenceSet : true ,
635+ } ) ;
636+ } ) ,
637+ ) ;
638+
529639 it . effect ( "stores sensitive provider instance environment values outside settings.json" , ( ) =>
530640 Effect . gen ( function * ( ) {
531641 const serverSettings = yield * ServerSettingsModule . ServerSettingsService ;
0 commit comments