@@ -228,3 +228,332 @@ def test_sync_default_prompt(cli_manager, tmp_path, monkeypatch):
228228 stored = cli_manager .get ("test" )
229229 assert stored .is_default is True
230230 assert any ("synced" in msg .lower () for msg in outputs )
231+
232+
233+ # Additional tests for uncovered functions
234+
235+
236+ def test_list_prompts_empty (cli_manager , monkeypatch ):
237+ """list_prompts shows message when no prompts exist."""
238+ outputs = []
239+ monkeypatch .setattr (
240+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
241+ )
242+
243+ prompts_commands .list_prompts ()
244+
245+ combined = "\n " .join (outputs )
246+ assert "No prompts found" in combined
247+
248+
249+ def test_list_prompts_with_prompts (cli_manager , monkeypatch ):
250+ """list_prompts shows all prompts with their status."""
251+ prompt1 = Prompt (id = "p1" , name = "Prompt One" , content = "content 1" )
252+ prompt2 = Prompt (
253+ id = "p2" , name = "Prompt Two" , content = "content 2" , description = "A description"
254+ )
255+ cli_manager .create (prompt1 )
256+ cli_manager .create (prompt2 )
257+ cli_manager .set_default ("p1" )
258+
259+ outputs = []
260+ monkeypatch .setattr (
261+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
262+ )
263+
264+ prompts_commands .list_prompts ()
265+
266+ combined = "\n " .join (outputs )
267+ assert "Prompt One" in combined
268+ assert "Prompt Two" in combined
269+ assert "default" in combined
270+ assert "p1" in combined
271+ assert "p2" in combined
272+ assert "A description" in combined
273+
274+
275+ def test_view_prompt_success (cli_manager , monkeypatch ):
276+ """view_prompt displays prompt content."""
277+ prompt = Prompt (
278+ id = "test" ,
279+ name = "Test Prompt" ,
280+ content = "This is the content" ,
281+ description = "A test description" ,
282+ )
283+ cli_manager .create (prompt )
284+
285+ outputs = []
286+ monkeypatch .setattr (
287+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
288+ )
289+
290+ prompts_commands .view_prompt ("test" )
291+
292+ combined = "\n " .join (outputs )
293+ assert "Test Prompt" in combined
294+ assert "This is the content" in combined
295+ assert "A test description" in combined
296+
297+
298+ def test_view_prompt_not_found (cli_manager , monkeypatch ):
299+ """view_prompt raises exit when prompt not found."""
300+ outputs = []
301+ monkeypatch .setattr (
302+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
303+ )
304+
305+ with pytest .raises (prompts_commands .typer .Exit ):
306+ prompts_commands .view_prompt ("nonexistent" )
307+
308+ combined = "\n " .join (outputs )
309+ assert "not found" in combined
310+
311+
312+ def test_create_prompt_from_file (cli_manager , tmp_path , monkeypatch ):
313+ """create_prompt reads content from file."""
314+ content_file = tmp_path / "content.md"
315+ content_file .write_text ("File content" )
316+
317+ outputs = []
318+ monkeypatch .setattr (
319+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
320+ )
321+
322+ prompts_commands .create_prompt (
323+ prompt_id = "new-prompt" ,
324+ name = "New Prompt" ,
325+ description = "From file" ,
326+ file = content_file ,
327+ )
328+
329+ prompt = cli_manager .get ("new-prompt" )
330+ assert prompt is not None
331+ assert prompt .content == "File content"
332+ assert prompt .name == "New Prompt"
333+ assert prompt .description == "From file"
334+
335+
336+ def test_create_prompt_empty_content (cli_manager , tmp_path , monkeypatch ):
337+ """create_prompt fails with empty content."""
338+ content_file = tmp_path / "empty.md"
339+ content_file .write_text ("" )
340+
341+ outputs = []
342+ monkeypatch .setattr (
343+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
344+ )
345+
346+ with pytest .raises (prompts_commands .typer .Exit ):
347+ prompts_commands .create_prompt (
348+ prompt_id = "empty-prompt" ,
349+ name = "Empty Prompt" ,
350+ description = None ,
351+ file = content_file ,
352+ )
353+
354+ combined = "\n " .join (outputs )
355+ assert "cannot be empty" in combined
356+
357+
358+ def test_update_prompt_success (cli_manager , tmp_path , monkeypatch ):
359+ """update_prompt updates existing prompt."""
360+ prompt = Prompt (id = "upd" , name = "Original" , content = "original content" )
361+ cli_manager .create (prompt )
362+
363+ new_content_file = tmp_path / "new_content.md"
364+ new_content_file .write_text ("updated content" )
365+
366+ outputs = []
367+ monkeypatch .setattr (
368+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
369+ )
370+
371+ prompts_commands .update_prompt (
372+ prompt_id = "upd" ,
373+ name = "Updated Name" ,
374+ description = "Updated desc" ,
375+ file = new_content_file ,
376+ )
377+
378+ updated = cli_manager .get ("upd" )
379+ assert updated .name == "Updated Name"
380+ assert updated .description == "Updated desc"
381+ assert updated .content == "updated content"
382+ assert any ("updated" in msg .lower () for msg in outputs )
383+
384+
385+ def test_update_prompt_not_found (cli_manager , monkeypatch ):
386+ """update_prompt fails when prompt not found."""
387+ outputs = []
388+ monkeypatch .setattr (
389+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
390+ )
391+
392+ with pytest .raises (prompts_commands .typer .Exit ):
393+ prompts_commands .update_prompt (
394+ prompt_id = "nonexistent" ,
395+ name = "New Name" ,
396+ description = None ,
397+ file = None ,
398+ )
399+
400+ combined = "\n " .join (outputs )
401+ assert "not found" in combined
402+
403+
404+ def test_delete_prompt_success (cli_manager , monkeypatch ):
405+ """delete_prompt removes prompt with force flag."""
406+ prompt = Prompt (id = "del" , name = "To Delete" , content = "content" )
407+ cli_manager .create (prompt )
408+
409+ outputs = []
410+ monkeypatch .setattr (
411+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
412+ )
413+
414+ prompts_commands .delete_prompt (prompt_id = "del" , force = True )
415+
416+ assert cli_manager .get ("del" ) is None
417+ assert any ("deleted" in msg .lower () for msg in outputs )
418+
419+
420+ def test_delete_prompt_not_found (cli_manager , monkeypatch ):
421+ """delete_prompt fails when prompt not found."""
422+ outputs = []
423+ monkeypatch .setattr (
424+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
425+ )
426+
427+ with pytest .raises (prompts_commands .typer .Exit ):
428+ prompts_commands .delete_prompt (prompt_id = "nonexistent" , force = True )
429+
430+ combined = "\n " .join (outputs )
431+ assert "not found" in combined
432+
433+
434+ def test_set_default_prompt_success (cli_manager , monkeypatch ):
435+ """set_default_prompt sets a prompt as default."""
436+ prompt = Prompt (id = "def" , name = "Default" , content = "content" )
437+ cli_manager .create (prompt )
438+
439+ outputs = []
440+ monkeypatch .setattr (
441+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
442+ )
443+
444+ prompts_commands .set_default_prompt (prompt_id = "def" )
445+
446+ updated = cli_manager .get ("def" )
447+ assert updated .is_default is True
448+ assert any ("default" in msg .lower () for msg in outputs )
449+
450+
451+ def test_set_default_prompt_not_found (cli_manager , monkeypatch ):
452+ """set_default_prompt fails when prompt not found."""
453+ outputs = []
454+ monkeypatch .setattr (
455+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
456+ )
457+
458+ with pytest .raises (prompts_commands .typer .Exit ):
459+ prompts_commands .set_default_prompt (prompt_id = "nonexistent" )
460+
461+ combined = "\n " .join (outputs )
462+ assert "not found" in combined
463+
464+
465+ def test_clear_default_prompt (cli_manager , monkeypatch ):
466+ """clear_default_prompt clears the default setting."""
467+ prompt = Prompt (id = "def" , name = "Default" , content = "content" )
468+ cli_manager .create (prompt )
469+ cli_manager .set_default ("def" )
470+
471+ outputs = []
472+ monkeypatch .setattr (
473+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
474+ )
475+
476+ prompts_commands .clear_default_prompt ()
477+
478+ updated = cli_manager .get ("def" )
479+ assert updated .is_default is False
480+ assert any ("cleared" in msg .lower () for msg in outputs )
481+
482+
483+ def test_generate_prompt_id ():
484+ """generate_prompt_id creates unique IDs with prefix."""
485+ id1 = prompts_commands .generate_prompt_id ("test" )
486+ id2 = prompts_commands .generate_prompt_id ("test" )
487+
488+ assert id1 .startswith ("test-" )
489+ assert id2 .startswith ("test-" )
490+ assert id1 != id2 # Should be unique
491+ assert len (id1 ) == len ("test-" ) + 8 # 8 char hex UUID
492+
493+
494+ def test_parse_app_list_all ():
495+ """_parse_app_list returns all apps when 'all' specified."""
496+ apps = prompts_commands ._parse_app_list ("all" )
497+ assert apps == prompts_commands .VALID_APP_TYPES
498+
499+
500+ def test_parse_app_list_comma_separated ():
501+ """_parse_app_list parses comma-separated apps."""
502+ apps = prompts_commands ._parse_app_list ("claude,codex" )
503+ assert apps == ["claude" , "codex" ]
504+
505+
506+ def test_parse_app_list_invalid ():
507+ """_parse_app_list raises error for invalid apps."""
508+ with pytest .raises (prompts_commands .typer .BadParameter ) as exc_info :
509+ prompts_commands ._parse_app_list ("invalid,claude" )
510+
511+ assert "invalid" in str (exc_info .value ).lower ()
512+
513+
514+ def test_unsync_prompt_project_level (cli_manager , tmp_path , monkeypatch ):
515+ """unsync_prompt clears project-level prompt file content."""
516+ project_dir = tmp_path / "project"
517+ project_dir .mkdir ()
518+ prompt_file = project_dir / "CLAUDE.md"
519+ prompt_file .write_text ("Content to unsync" )
520+
521+ outputs = []
522+ monkeypatch .setattr (
523+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
524+ )
525+
526+ prompts_commands .unsync_prompt (
527+ app_type = "claude" ,
528+ level = "project" ,
529+ force = True ,
530+ project_dir = project_dir ,
531+ )
532+
533+ # unsync clears the file content, not deletes it
534+ assert prompt_file .exists ()
535+ assert prompt_file .read_text () == ""
536+ combined = "\n " .join (outputs )
537+ assert "cleared" in combined .lower ()
538+
539+
540+ def test_unsync_prompt_file_not_found (cli_manager , tmp_path , monkeypatch ):
541+ """unsync_prompt handles missing file gracefully."""
542+ project_dir = tmp_path / "project"
543+ project_dir .mkdir ()
544+
545+ outputs = []
546+ monkeypatch .setattr (
547+ prompts_commands .typer , "echo" , lambda msg = "" : outputs .append (str (msg ))
548+ )
549+
550+ prompts_commands .unsync_prompt (
551+ app_type = "claude" ,
552+ level = "project" ,
553+ force = True ,
554+ project_dir = project_dir ,
555+ )
556+
557+ combined = "\n " .join (outputs )
558+ # Should indicate file doesn't exist
559+ assert "not exist" in combined .lower () or "does not exist" in combined .lower ()
0 commit comments