From 3f787ec66d30bcfa94204d14ff4786da179d1581 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Sun, 7 Jun 2026 15:55:04 +0800 Subject: [PATCH] fix: only plugins with on_install are managed - skip others entirely - Discover(): skip plugins without on_install hook (not shown in UI) - Enable(): simplified - just check Installed flag - SyncConfig(): simplified - no HasInstall special case - Frontend: simplified toggle logic (only installed/uninstalled states) - Tests: updated all test fixtures to include on_install hook --- frontend/src/lib/SettingsPlugins.svelte | 14 ++----------- internal/core/plugins/manager.go | 28 ++++++++++++------------- internal/core/plugins/manager_test.go | 20 +++++++++++------- internal/core/plugins/runtime_test.go | 3 ++- 4 files changed, 30 insertions(+), 35 deletions(-) diff --git a/frontend/src/lib/SettingsPlugins.svelte b/frontend/src/lib/SettingsPlugins.svelte index 35ef162..424177e 100644 --- a/frontend/src/lib/SettingsPlugins.svelte +++ b/frontend/src/lib/SettingsPlugins.svelte @@ -107,11 +107,11 @@
- {#if p.hasInstall && !p.installed} + {#if !p.installed} - {:else if p.hasInstall && p.installed} + {:else}
- {:else} - {/if}
diff --git a/internal/core/plugins/manager.go b/internal/core/plugins/manager.go index 28ff4e6..b5067e7 100644 --- a/internal/core/plugins/manager.go +++ b/internal/core/plugins/manager.go @@ -130,14 +130,18 @@ func (m *Manager) Discover() { os.MkdirAll(dataDir, 0o750) hasInstall := meta.Hooks["on_install"] != "" + if !hasInstall { + log.Printf("[plugins] %s: skipping — no on_install hook (not a managed plugin)", e.Name()) + continue + } m.plugins = append(m.plugins, Plugin{ - Meta: meta, - Dir: filepath.Join(pluginsDir, e.Name()), - DataDir: dataDir, - Active: false, - Installed: false, - HasInstall: hasInstall, + Meta: meta, + Dir: filepath.Join(pluginsDir, e.Name()), + DataDir: dataDir, + Active: false, + Installed: false, + HasInstall: true, }) } } @@ -158,10 +162,6 @@ func (m *Manager) SyncConfig(cfg *config.AppConfig) { } for i := range m.plugins { installed := installedSet[m.plugins[i].Meta.Name] - // Plugins without on_install hook are always "installed" - if !m.plugins[i].HasInstall { - installed = true - } m.plugins[i].Installed = installed m.plugins[i].Active = installed && enabledSet[m.plugins[i].Meta.Name] } @@ -352,16 +352,14 @@ type NodeMeta struct { Type string `json:"type"` // text, url, etc. } -// Enable activates a plugin by name. -// If the plugin has on_install hook, it must be installed first. +// Enable activates a plugin by name. Plugin must be installed first. func (m *Manager) Enable(name string) error { for i := range m.plugins { if m.plugins[i].Meta.Name == name { - p := &m.plugins[i] - if p.HasInstall && !p.Installed { + if !m.plugins[i].Installed { return fmt.Errorf("plugin %q must be installed first", name) } - p.Active = true + m.plugins[i].Active = true return nil } } diff --git a/internal/core/plugins/manager_test.go b/internal/core/plugins/manager_test.go index 997b687..ae16b80 100644 --- a/internal/core/plugins/manager_test.go +++ b/internal/core/plugins/manager_test.go @@ -41,7 +41,8 @@ func TestDiscover(t *testing.T) { "plugin.json": []byte(`{ "name": "client", "version": "1.0.0", - "description": "Client template", + "description": "Client plugin", + "hooks": { "on_install": "on_install" }, "templates": ["client"] }`), }, @@ -78,7 +79,8 @@ func TestDiscover(t *testing.T) { t.Errorf("plugin name = %q", plugins[0].Meta.Name) } - // Enable plugin to load templates + // Install & enable plugin to load templates + mgr.Install("client") mgr.Enable("client") // Templates. @@ -104,12 +106,12 @@ func TestEnableDisable(t *testing.T) { root := setupPluginDir(t, map[string]*fsDir{ "plugin-a": { files: map[string][]byte{ - "plugin.json": []byte(`{"name": "a", "version": "1.0"}`), + "plugin.json": []byte(`{"name": "a", "version": "1.0", "hooks": {"on_install": "on_install"}}`), }, }, "plugin-b": { files: map[string][]byte{ - "plugin.json": []byte(`{"name": "b", "version": "1.0"}`), + "plugin.json": []byte(`{"name": "b", "version": "1.0", "hooks": {"on_install": "on_install"}}`), }, }, }) @@ -126,7 +128,9 @@ func TestEnableDisable(t *testing.T) { t.Errorf("active after discover = %d, want 0", len(mgr.Active())) } - // Enable both. + // Install & enable both. + mgr.Install("a") + mgr.Install("b") mgr.Enable("a") mgr.Enable("b") if len(mgr.Active()) != 2 { @@ -148,12 +152,14 @@ func TestEnableDisable(t *testing.T) { func TestActiveNames(t *testing.T) { root := setupPluginDir(t, map[string]*fsDir{ - "p1": {files: map[string][]byte{"plugin.json": []byte(`{"name":"p1"}`)}}, - "p2": {files: map[string][]byte{"plugin.json": []byte(`{"name":"p2"}`)}}, + "p1": {files: map[string][]byte{"plugin.json": []byte(`{"name":"p1","hooks":{"on_install":"on_install"}}`)}}, + "p2": {files: map[string][]byte{"plugin.json": []byte(`{"name":"p2","hooks":{"on_install":"on_install"}}`)}}, }) mgr := NewManager(root) mgr.Discover() + mgr.Install("p1") + mgr.Install("p2") mgr.Enable("p1") mgr.Enable("p2") mgr.Disable("p1") diff --git a/internal/core/plugins/runtime_test.go b/internal/core/plugins/runtime_test.go index 6dd7e4b..876f725 100644 --- a/internal/core/plugins/runtime_test.go +++ b/internal/core/plugins/runtime_test.go @@ -215,7 +215,7 @@ func TestPluginManager_InitRuntimes(t *testing.T) { pj := `{ "name": "testp", "version": "1.0.0", - "hooks": { "on_init": "on_init" } + "hooks": { "on_install": "on_install", "on_init": "on_init" } }` if err := os.WriteFile(filepath.Join(pluginsDir, "plugin.json"), []byte(pj), 0644); err != nil { t.Fatal(err) @@ -228,6 +228,7 @@ func TestPluginManager_InitRuntimes(t *testing.T) { mgr := NewManager(dir) mgr.Discover() + mgr.Install("testp") mgr.Enable("testp") mgr.InitRuntimes() defer mgr.CloseRuntimes()