File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -766,12 +766,12 @@ Percentages are **statement coverage** from a merged profile (`go test -coverpro
766766| ` plugin/license ` | 87.1% | 203 LOC | High |
767767| ` client/crypto ` | 80.3% | 320 LOC | High |
768768| ` config ` | 73.2% | 285 LOC | High |
769- | ` plugin/host ` | 62.5% | 536 LOC | Medium |
769+ | ` plugin/host ` | 62.5% | 539 LOC | Medium |
770770| ` client/config ` | 57.3% | 1683 LOC | Medium |
771771| ` internal/doctor ` | 49.8% | 661 LOC | Medium |
772772| ` plugin/store ` | 47.0% | 490 LOC | Medium |
773773| ` cmd/license ` | 42.2% | 140 LOC | Medium |
774- | ` server ` | 36.1% | 6310 LOC | Low |
774+ | ` server ` | 36.1% | 6303 LOC | Low |
775775| ` plugin/manager ` | 32.1% | 626 LOC | Low |
776776| ` client ` | 23.0% | 4966 LOC | Low |
777777| ` cmd/server ` | 13.7% | 424 LOC | Low |
Original file line number Diff line number Diff line change @@ -174,12 +174,12 @@ go test -cover ./...
174174| ` plugin/license ` | 87.1% | High | 203 | Small |
175175| ` client/crypto ` | 80.3% | High | 320 | Small |
176176| ` config ` | 73.2% | High | 285 | Small |
177- | ` plugin/host ` | 62.5% | Medium | 536 | Medium |
177+ | ` plugin/host ` | 62.5% | Medium | 539 | Medium |
178178| ` client/config ` | 57.3% | Medium | 1683 | Medium |
179179| ` internal/doctor ` | 49.8% | Medium | 661 | Medium |
180180| ` plugin/store ` | 47.0% | Medium | 490 | Medium |
181181| ` cmd/license ` | 42.2% | Medium | 140 | Small |
182- | ` server ` | 36.1% | Low | 6310 | Large |
182+ | ` server ` | 36.1% | Low | 6303 | Large |
183183| ` plugin/manager ` | 32.1% | Low | 626 | Medium |
184184| ` client ` | 23.0% | Low | 4966 | Large |
185185| ` cmd/server ` | 13.7% | Low | 424 | Medium |
Original file line number Diff line number Diff line change @@ -244,9 +244,11 @@ func (h *PluginHost) StartPlugin(name string) error {
244244 return fmt .Errorf ("failed to initialize plugin %s: %w" , name , err )
245245 }
246246
247- // Start communication goroutines
247+ // Start communication goroutines.
248+ // Stderr is captured as a function arg so StopPlugin can safely nil the
249+ // struct field without racing the goroutine's first read.
248250 go h .handlePluginOutput (instance )
249- go h .handlePluginErrors (instance )
251+ go h .handlePluginErrors (instance , instance . Stderr )
250252
251253 log .Printf ("Plugin %s started successfully" , name )
252254 return nil
@@ -542,9 +544,10 @@ func (h *PluginHost) handlePluginOutput(instance *PluginInstance) {
542544 }
543545}
544546
545- // handlePluginErrors handles stderr from a plugin
546- func (h * PluginHost ) handlePluginErrors (instance * PluginInstance ) {
547- scanner := json .NewDecoder (instance .Stderr )
547+ // handlePluginErrors handles stderr from a plugin.
548+ // stderr is passed explicitly to avoid racing StopPlugin's nil-out of the field.
549+ func (h * PluginHost ) handlePluginErrors (instance * PluginInstance , stderr io.Reader ) {
550+ scanner := json .NewDecoder (stderr )
548551 for {
549552 var logEntry struct {
550553 Level string `json:"level"`
Original file line number Diff line number Diff line change @@ -402,14 +402,7 @@ func (h *Hub) Run() {
402402 // Start plugin message handler goroutine
403403 go func () {
404404 for msg := range h .pluginManager .GetMessageChannel () {
405- // Route plugin messages through the broadcast channel for safe access
406- sharedMsg := shared.Message {
407- Sender : msg .Sender ,
408- Content : msg .Content ,
409- CreatedAt : msg .CreatedAt ,
410- Type : shared .TextMessage ,
411- }
412- h .broadcast <- sharedMsg
405+ h .broadcast <- ConvertPluginMessage (msg )
413406 }
414407 }()
415408
You can’t perform that action at this time.
0 commit comments