fix(plugins): restore plugin runtimes on startup + graceful shutdown
Root cause: initVault() called Discover() but never called SyncConfig(), InitRuntimes(), CallInitHooks(), or StartSchedulers(). On restart, plugins were discovered from disk but their config state (Installed/Enabled) was not restored and no Lua VMs were created. This caused: - Settings → Plugins showing plugins as 'not installed' after restart - Sidebar showing calendar item (from enabledSet config) but GetPluginPanelHTML failing (only checked p.Active) - Toggle working in-session but state lost on restart - closeVault() not stopping plugin schedulers/shutdown/VM (leak) Fixes: - bindings_config.go: add SyncConfig(appCfg) after Discover() - bindings_config.go: add InitRuntimes() + CallInitHooks() + StartSchedulers() after watcher start - bindings_config.go: add StopSchedulers + CallShutdownHooks + CloseRuntimes to closeVault() (before db.Close since plugins use DB) - bindings_plugins.go: GetPluginPanelHTML now checks enabledSet || p.Active, consistent with ListSystemViewsWithPlugins and ListPlugins
This commit is contained in:
parent
f769daa617
commit
d6e28d7b1f
|
|
@ -228,6 +228,9 @@ func (a *App) initVault(vaultPath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply installed/enabled state from config to discovered plugins
|
||||||
|
pm.SyncConfig(appCfg)
|
||||||
|
|
||||||
// Sync service
|
// Sync service
|
||||||
deviceID := ""
|
deviceID := ""
|
||||||
_ = appCfg // will store sync settings
|
_ = appCfg // will store sync settings
|
||||||
|
|
@ -292,6 +295,11 @@ func (a *App) initVault(vaultPath string) error {
|
||||||
// Start auto-sync loop
|
// Start auto-sync loop
|
||||||
go a.autoSyncLoop()
|
go a.autoSyncLoop()
|
||||||
|
|
||||||
|
// Start plugin runtimes for enabled plugins (creates VM, loads scripts, calls on_init)
|
||||||
|
pm.InitRuntimes()
|
||||||
|
pm.CallInitHooks()
|
||||||
|
pm.StartSchedulers()
|
||||||
|
|
||||||
// Start bridge server for browser extension integration (if enabled).
|
// Start bridge server for browser extension integration (if enabled).
|
||||||
if appCfg == nil || appCfg.Vault.Bridge.Enabled {
|
if appCfg == nil || appCfg.Vault.Bridge.Enabled {
|
||||||
a.startBridge(appCfg)
|
a.startBridge(appCfg)
|
||||||
|
|
@ -313,6 +321,12 @@ func (a *App) closeVault() {
|
||||||
if a.fileWatcher != nil {
|
if a.fileWatcher != nil {
|
||||||
a.fileWatcher.Stop()
|
a.fileWatcher.Stop()
|
||||||
}
|
}
|
||||||
|
// Stop plugin runtimes (schedulers → on_shutdown → close VMs)
|
||||||
|
if a.plugins != nil {
|
||||||
|
a.plugins.StopSchedulers()
|
||||||
|
a.plugins.CallShutdownHooks()
|
||||||
|
a.plugins.CloseRuntimes()
|
||||||
|
}
|
||||||
// Stop bridge server.
|
// Stop bridge server.
|
||||||
if a.bridge != nil {
|
if a.bridge != nil {
|
||||||
a.bridge.Stop()
|
a.bridge.Stop()
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,16 @@ func (a *App) GetPluginPanelHTML(pluginName string) (string, error) {
|
||||||
if a.plugins == nil {
|
if a.plugins == nil {
|
||||||
return "", fmt.Errorf("plugin manager not ready")
|
return "", fmt.Errorf("plugin manager not ready")
|
||||||
}
|
}
|
||||||
|
appCfg, _ := config.LoadAppConfig()
|
||||||
|
enabledSet := make(map[string]bool)
|
||||||
|
if appCfg != nil {
|
||||||
|
for _, name := range appCfg.EnabledPlugins {
|
||||||
|
enabledSet[name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, p := range a.plugins.Plugins() {
|
for _, p := range a.plugins.Plugins() {
|
||||||
if p.Meta.Name != pluginName || !p.Active {
|
active := enabledSet[p.Meta.Name] || p.Active
|
||||||
|
if p.Meta.Name != pluginName || !active {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.Meta.Panel == "" {
|
if p.Meta.Panel == "" {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue