11import { mkdtempSync , readFileSync , rmSync , writeFileSync } from 'node:fs' ;
22import { tmpdir } from 'node:os' ;
33import { join } from 'node:path' ;
4- import { describe , expect , it } from 'vitest' ;
4+ import { describe , expect , it , vi } from 'vitest' ;
55
66import {
77 getCustomProviderId ,
@@ -24,6 +24,7 @@ function createSettings(overrides?: Partial<GlobalSettings>): GlobalSettings {
2424 version : 0 ,
2525 modePackId : null ,
2626 omPackId : null ,
27+ quietModePreferenceSelected : true ,
2728 } ,
2829 models : {
2930 activeModelPackId : 'anthropic' ,
@@ -37,8 +38,10 @@ function createSettings(overrides?: Partial<GlobalSettings>): GlobalSettings {
3738 omCavemanObservations : null ,
3839 omObserveAttachments : null ,
3940 subagentModels : { } ,
41+ goalJudgeModel : null ,
42+ goalMaxTurns : null ,
4043 } ,
41- preferences : { yolo : null , theme : 'auto' , thinkingLevel : 'off' , quietMode : false } ,
44+ preferences : { yolo : null , theme : 'auto' , thinkingLevel : 'off' , quietMode : false , quietModeMaxToolPreviewLines : 2 } ,
4245 storage,
4346 customProviders : [ ] ,
4447 customModelPacks : [
@@ -62,6 +65,7 @@ function createSettings(overrides?: Partial<GlobalSettings>): GlobalSettings {
6265 viewport : { width : 1280 , height : 720 } ,
6366 stagehand : { env : 'LOCAL' } ,
6467 } ,
68+ observability : { resources : { } , localTracing : false } ,
6569 ...overrides ,
6670 } ;
6771}
@@ -104,6 +108,110 @@ describe('customProviders parsing/persistence', () => {
104108
105109 expect ( settings . customProviders ) . toEqual ( [ ] ) ;
106110 expect ( settings . preferences . thinkingLevel ) . toBe ( 'off' ) ;
111+ expect ( settings . preferences . quietModeMaxToolPreviewLines ) . toBe ( 2 ) ;
112+ } ) ;
113+ } ) ;
114+
115+ it ( 'normalizes quiet mode preview line limits' , ( ) => {
116+ withTempSettingsFile ( filePath => {
117+ writeFileSync (
118+ filePath ,
119+ JSON . stringify ( { onboarding : { } , models : { } , preferences : { quietModeMaxToolPreviewLines : 2.9 } , storage : { } } ) ,
120+ 'utf-8' ,
121+ ) ;
122+ expect ( loadSettings ( filePath ) . preferences . quietModeMaxToolPreviewLines ) . toBe ( 2 ) ;
123+
124+ writeFileSync (
125+ filePath ,
126+ JSON . stringify ( { onboarding : { } , models : { } , preferences : { quietModeMaxToolPreviewLines : - 4 } , storage : { } } ) ,
127+ 'utf-8' ,
128+ ) ;
129+ expect ( loadSettings ( filePath ) . preferences . quietModeMaxToolPreviewLines ) . toBe ( 0 ) ;
130+
131+ writeFileSync (
132+ filePath ,
133+ JSON . stringify ( { onboarding : { } , models : { } , preferences : { quietModeMaxToolPreviewLines : 999 } , storage : { } } ) ,
134+ 'utf-8' ,
135+ ) ;
136+ expect ( loadSettings ( filePath ) . preferences . quietModeMaxToolPreviewLines ) . toBe ( 8 ) ;
137+
138+ writeFileSync ( filePath , '{}' , 'utf-8' ) ;
139+ vi . spyOn ( JSON , 'parse' ) . mockReturnValueOnce ( {
140+ onboarding : { quietModePreferenceSelected : true } ,
141+ models : { } ,
142+ preferences : { quietModeMaxToolPreviewLines : Number . NaN } ,
143+ storage : { } ,
144+ } ) ;
145+ expect ( loadSettings ( filePath ) . preferences . quietModeMaxToolPreviewLines ) . toBe ( 2 ) ;
146+ vi . mocked ( JSON . parse ) . mockRestore ( ) ;
147+
148+ vi . spyOn ( JSON , 'parse' ) . mockReturnValueOnce ( {
149+ onboarding : { quietModePreferenceSelected : true } ,
150+ models : { } ,
151+ preferences : { quietModeMaxToolPreviewLines : Number . POSITIVE_INFINITY } ,
152+ storage : { } ,
153+ } ) ;
154+ expect ( loadSettings ( filePath ) . preferences . quietModeMaxToolPreviewLines ) . toBe ( 2 ) ;
155+ vi . mocked ( JSON . parse ) . mockRestore ( ) ;
156+ } ) ;
157+ } ) ;
158+
159+ it ( 'defaults new installs to quiet mode with the preference selected' , ( ) => {
160+ withTempSettingsFile ( filePath => {
161+ const settings = loadSettings ( filePath ) ;
162+
163+ expect ( settings . preferences . quietMode ) . toBe ( true ) ;
164+ expect ( settings . onboarding . quietModePreferenceSelected ) . toBe ( true ) ;
165+ } ) ;
166+ } ) ;
167+
168+ it ( 'marks existing classic users as needing the quiet mode preference prompt' , ( ) => {
169+ withTempSettingsFile ( filePath => {
170+ writeFileSync (
171+ filePath ,
172+ JSON . stringify ( { onboarding : { } , models : { } , preferences : { quietMode : false } , storage : { } } ) ,
173+ 'utf-8' ,
174+ ) ;
175+
176+ const settings = loadSettings ( filePath ) ;
177+
178+ expect ( settings . preferences . quietMode ) . toBe ( false ) ;
179+ expect ( settings . onboarding . quietModePreferenceSelected ) . toBe ( false ) ;
180+ } ) ;
181+ } ) ;
182+
183+ it ( 'does not prompt existing users who already enabled quiet mode' , ( ) => {
184+ withTempSettingsFile ( filePath => {
185+ writeFileSync (
186+ filePath ,
187+ JSON . stringify ( { onboarding : { } , models : { } , preferences : { quietMode : true } , storage : { } } ) ,
188+ 'utf-8' ,
189+ ) ;
190+
191+ const settings = loadSettings ( filePath ) ;
192+
193+ expect ( settings . preferences . quietMode ) . toBe ( true ) ;
194+ expect ( settings . onboarding . quietModePreferenceSelected ) . toBe ( true ) ;
195+ } ) ;
196+ } ) ;
197+
198+ it ( 'preserves existing quiet mode preference selections' , ( ) => {
199+ withTempSettingsFile ( filePath => {
200+ writeFileSync (
201+ filePath ,
202+ JSON . stringify ( {
203+ onboarding : { quietModePreferenceSelected : true } ,
204+ models : { } ,
205+ preferences : { quietMode : false } ,
206+ storage : { } ,
207+ } ) ,
208+ 'utf-8' ,
209+ ) ;
210+
211+ const settings = loadSettings ( filePath ) ;
212+
213+ expect ( settings . preferences . quietMode ) . toBe ( false ) ;
214+ expect ( settings . onboarding . quietModePreferenceSelected ) . toBe ( true ) ;
107215 } ) ;
108216 } ) ;
109217
0 commit comments