@@ -3,6 +3,7 @@ package plugin
33import (
44 "os"
55 "path/filepath"
6+ "strings"
67 "testing"
78)
89
@@ -401,16 +402,26 @@ func TestParsePluginMD_GitHubSheriff(t *testing.T) {
401402
402403func TestParsePluginMD_SessionHygiene (t * testing.T ) {
403404 // Verify the actual session-hygiene plugin.md parses correctly.
404- content , err := os .ReadFile (filepath .Join (".." , ".." , "plugins" , "session-hygiene" , "plugin.md" ))
405+ pluginDir := filepath .Join (".." , ".." , "plugins" , "session-hygiene" )
406+ content , err := os .ReadFile (filepath .Join (pluginDir , "plugin.md" ))
405407 if err != nil {
406408 t .Skipf ("session-hygiene plugin not found (expected in plugins/): %v" , err )
407409 }
408410
409- plugin , err := parsePluginMD (content , "/test/session-hygiene" , LocationRig , "gastown" )
411+ plugin , err := parsePluginMD (content , pluginDir , LocationRig , "gastown" )
410412 if err != nil {
411413 t .Fatalf ("parsePluginMD failed: %v" , err )
412414 }
413415
416+ // Verify run.sh detection (loadPlugin does this, not parsePluginMD)
417+ runScriptPath := filepath .Join (pluginDir , "run.sh" )
418+ if info , statErr := os .Stat (runScriptPath ); statErr == nil && ! info .IsDir () {
419+ plugin .HasRunScript = true
420+ }
421+ if ! plugin .HasRunScript {
422+ t .Error ("expected HasRunScript=true for session-hygiene (has run.sh)" )
423+ }
424+
414425 if plugin .Name != "session-hygiene" {
415426 t .Errorf ("expected name 'session-hygiene', got %q" , plugin .Name )
416427 }
@@ -509,3 +520,123 @@ version = 1
509520 t .Errorf ("expected location 'rig', got %q" , plugins [0 ].Location )
510521 }
511522}
523+
524+ func TestLoadPlugin_DetectsRunScript (t * testing.T ) {
525+ tmpDir , err := os .MkdirTemp ("" , "plugin-runsh-test" )
526+ if err != nil {
527+ t .Fatalf ("failed to create temp dir: %v" , err )
528+ }
529+ defer os .RemoveAll (tmpDir )
530+
531+ // Create plugin dir with plugin.md AND run.sh
532+ pluginDir := filepath .Join (tmpDir , "plugins" , "with-script" )
533+ if err := os .MkdirAll (pluginDir , 0755 ); err != nil {
534+ t .Fatalf ("failed to create plugin dir: %v" , err )
535+ }
536+ pluginContent := []byte (`+++
537+ name = "with-script"
538+ description = "Plugin with run.sh"
539+ version = 1
540+ +++
541+
542+ # Instructions (should be ignored when run.sh exists)
543+ ` )
544+ if err := os .WriteFile (filepath .Join (pluginDir , "plugin.md" ), pluginContent , 0644 ); err != nil {
545+ t .Fatalf ("failed to write plugin.md: %v" , err )
546+ }
547+ if err := os .WriteFile (filepath .Join (pluginDir , "run.sh" ), []byte ("#!/bin/bash\n echo hello\n " ), 0755 ); err != nil {
548+ t .Fatalf ("failed to write run.sh: %v" , err )
549+ }
550+
551+ // Create plugin dir with plugin.md only (no run.sh)
552+ pluginDirNoScript := filepath .Join (tmpDir , "plugins" , "no-script" )
553+ if err := os .MkdirAll (pluginDirNoScript , 0755 ); err != nil {
554+ t .Fatalf ("failed to create plugin dir: %v" , err )
555+ }
556+ noScriptContent := []byte (`+++
557+ name = "no-script"
558+ description = "Plugin without run.sh"
559+ version = 1
560+ +++
561+
562+ # Instructions
563+ ` )
564+ if err := os .WriteFile (filepath .Join (pluginDirNoScript , "plugin.md" ), noScriptContent , 0644 ); err != nil {
565+ t .Fatalf ("failed to write plugin.md: %v" , err )
566+ }
567+
568+ scanner := NewScanner (tmpDir , nil )
569+ plugins , err := scanner .DiscoverAll ()
570+ if err != nil {
571+ t .Fatalf ("DiscoverAll failed: %v" , err )
572+ }
573+
574+ if len (plugins ) != 2 {
575+ t .Fatalf ("expected 2 plugins, got %d" , len (plugins ))
576+ }
577+
578+ byName := make (map [string ]* Plugin )
579+ for _ , p := range plugins {
580+ byName [p .Name ] = p
581+ }
582+
583+ if p , ok := byName ["with-script" ]; ! ok {
584+ t .Fatal ("expected to find 'with-script' plugin" )
585+ } else if ! p .HasRunScript {
586+ t .Error ("expected HasRunScript=true for plugin with run.sh" )
587+ }
588+
589+ if p , ok := byName ["no-script" ]; ! ok {
590+ t .Fatal ("expected to find 'no-script' plugin" )
591+ } else if p .HasRunScript {
592+ t .Error ("expected HasRunScript=false for plugin without run.sh" )
593+ }
594+ }
595+
596+ func TestFormatMailBody_WithRunScript (t * testing.T ) {
597+ p := & Plugin {
598+ Name : "test-plugin" ,
599+ Description : "A test plugin" ,
600+ Path : "/home/user/gt/plugins/test-plugin" ,
601+ HasRunScript : true ,
602+ }
603+
604+ body := p .FormatMailBody ()
605+
606+ // Must contain the bash command to run the script
607+ if ! strings .Contains (body , "cd /home/user/gt/plugins/test-plugin && bash run.sh" ) {
608+ t .Error ("expected mail body to contain run.sh execution command" )
609+ }
610+ // Must instruct dog NOT to interpret markdown
611+ if ! strings .Contains (body , "Do NOT interpret the plugin.md instructions" ) {
612+ t .Error ("expected mail body to warn against interpreting markdown" )
613+ }
614+ // Must NOT contain "## Instructions" section
615+ if strings .Contains (body , "## Instructions" ) {
616+ t .Error ("expected mail body to NOT contain markdown instructions section" )
617+ }
618+ }
619+
620+ func TestFormatMailBody_WithoutRunScript (t * testing.T ) {
621+ p := & Plugin {
622+ Name : "test-plugin" ,
623+ Description : "A test plugin" ,
624+ Path : "/home/user/gt/plugins/test-plugin" ,
625+ Instructions : "Do the thing." ,
626+ HasRunScript : false ,
627+ }
628+
629+ body := p .FormatMailBody ()
630+
631+ // Must contain the instructions section
632+ if ! strings .Contains (body , "## Instructions" ) {
633+ t .Error ("expected mail body to contain instructions section" )
634+ }
635+ if ! strings .Contains (body , "Do the thing." ) {
636+ t .Error ("expected mail body to contain plugin instructions" )
637+ }
638+ // Must NOT contain run.sh dispatch
639+ if strings .Contains (body , "bash run.sh" ) {
640+ t .Error ("expected mail body to NOT contain run.sh command" )
641+ }
642+ }
0 commit comments