@@ -134,11 +134,91 @@ def write_config(config_path: Path, state: dict) -> None:
134134
135135def usage () -> int :
136136 print (
137- "usage: /notify status | /notify help | /notify profile <all|quiet|focus|sound-only|visual-only> | /notify enable <all|sound|visual|complete|error|permission|question> | /notify disable <all|sound|visual|complete|error|permission|question> | /notify channel <complete|error|permission|question> <sound|visual> <on|off>"
137+ "usage: /notify status | /notify help | /notify doctor [--json] | /notify profile <all|quiet|focus|sound-only|visual-only> | /notify enable <all|sound|visual|complete|error|permission|question> | /notify disable <all|sound|visual|complete|error|permission|question> | /notify channel <complete|error|permission|question> <sound|visual> <on|off>"
138138 )
139139 return 2
140140
141141
142+ def collect_doctor (config_path : Path , state : dict ) -> dict :
143+ problems : list [str ] = []
144+ warnings : list [str ] = []
145+
146+ if not config_path .exists ():
147+ warnings .append ("notification config file not found yet (using defaults)" )
148+
149+ if not state ["enabled" ]:
150+ warnings .append ("global notifications are disabled" )
151+
152+ if not state ["sound" ]["enabled" ] and not state ["visual" ]["enabled" ]:
153+ warnings .append ("both sound and visual channels are disabled" )
154+
155+ enabled_events = [name for name in EVENTS if state ["events" ][name ]]
156+ if not enabled_events :
157+ warnings .append ("all events are disabled" )
158+
159+ for event in EVENTS :
160+ if state ["events" ][event ] and not (
161+ state ["channels" ][event ]["sound" ] or state ["channels" ][event ]["visual" ]
162+ ):
163+ warnings .append (
164+ f"event { event } is enabled but both per-event channels are off"
165+ )
166+
167+ return {
168+ "result" : "PASS" if not problems else "FAIL" ,
169+ "config" : str (config_path ),
170+ "enabled" : state ["enabled" ],
171+ "sound_enabled" : state ["sound" ]["enabled" ],
172+ "visual_enabled" : state ["visual" ]["enabled" ],
173+ "events" : state ["events" ],
174+ "channels" : state ["channels" ],
175+ "warnings" : warnings ,
176+ "problems" : problems ,
177+ "quick_fixes" : [
178+ "run /notify profile focus for low-noise defaults" ,
179+ "run /notify enable visual or /notify enable sound" ,
180+ "run /notify enable permission or /notify enable error" ,
181+ ]
182+ if warnings or problems
183+ else [],
184+ }
185+
186+
187+ def print_doctor (config_path : Path , state : dict , json_output : bool ) -> int :
188+ report = collect_doctor (config_path , state )
189+
190+ if json_output :
191+ print (json .dumps (report , indent = 2 ))
192+ return 0 if report ["result" ] == "PASS" else 1
193+
194+ print ("notify doctor" )
195+ print ("-----------" )
196+ print (f"config: { report ['config' ]} " )
197+ print (f"global: { 'enabled' if report ['enabled' ] else 'disabled' } " )
198+ print (f"sound: { 'enabled' if report ['sound_enabled' ] else 'disabled' } " )
199+ print (f"visual: { 'enabled' if report ['visual_enabled' ] else 'disabled' } " )
200+ print ("events:" )
201+ for event in EVENTS :
202+ print (
203+ f"- { event } : { 'enabled' if state ['events' ][event ] else 'disabled' } [sound={ 'on' if state ['channels' ][event ]['sound' ] else 'off' } , visual={ 'on' if state ['channels' ][event ]['visual' ] else 'off' } ]"
204+ )
205+
206+ if report ["warnings" ]:
207+ print ("\n warnings:" )
208+ for item in report ["warnings" ]:
209+ print (f"- { item } " )
210+
211+ if report ["problems" ]:
212+ print ("\n problems:" )
213+ for item in report ["problems" ]:
214+ print (f"- { item } " )
215+ print ("\n result: FAIL" )
216+ return 1
217+
218+ print ("\n result: PASS" )
219+ return 0
220+
221+
142222def print_status (config_path : Path , state : dict ) -> int :
143223 print (f"all: { 'enabled' if state ['enabled' ] else 'disabled' } " )
144224 print (f"sound: { 'enabled' if state ['sound' ]['enabled' ] else 'disabled' } " )
@@ -215,6 +295,12 @@ def main(argv: list[str]) -> int:
215295 if argv [0 ] == "help" :
216296 return usage ()
217297
298+ if argv [0 ] == "doctor" :
299+ json_output = len (argv ) > 1 and argv [1 ] == "--json"
300+ if len (argv ) > 1 and not json_output :
301+ return usage ()
302+ return print_doctor (config_path , state , json_output )
303+
218304 if argv [0 ] == "profile" :
219305 if len (argv ) < 2 :
220306 return usage ()
0 commit comments