Compare commits

...

1 Commits

Author SHA1 Message Date
Gregory Schier
50c7992b42 Unify plugin bootstrap and prep vendored assets in CLI release 2026-02-22 15:01:34 -08:00
7 changed files with 131 additions and 89 deletions

View File

@@ -14,8 +14,39 @@ permissions:
contents: read
jobs:
prepare-vendored-assets:
name: Prepare vendored plugin assets
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Build plugin assets
run: |
npm run build-plugins
npm run vendor:vendor-plugins
- name: Upload vendored assets
uses: actions/upload-artifact@v4
with:
name: vendored-assets
path: |
crates-tauri/yaak-app/vendored/plugin-runtime/index.cjs
crates-tauri/yaak-app/vendored/plugins
if-no-files-found: error
build-binaries:
name: Build ${{ matrix.pkg }}
needs: prepare-vendored-assets
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
@@ -67,6 +98,12 @@ jobs:
sudo apt-get update
sudo apt-get install -y pkg-config libdbus-1-dev
- name: Download vendored assets
uses: actions/download-artifact@v4
with:
name: vendored-assets
path: crates-tauri/yaak-app/vendored
- name: Build yaak
run: cargo build --locked --release -p yaak-cli --bin yaak --target ${{ matrix.target }}

View File

@@ -8,6 +8,7 @@ use yaak_crypto::manager::EncryptionManager;
use yaak_models::blob_manager::BlobManager;
use yaak_models::db_context::DbContext;
use yaak_models::query_manager::QueryManager;
use yaak_plugins::bootstrap;
use yaak_plugins::events::PluginContext;
use yaak_plugins::manager::PluginManager;
@@ -51,38 +52,23 @@ impl CliContext {
.expect("Failed to prepare embedded plugin runtime")
});
let plugin_manager = Arc::new(
PluginManager::new(
vendored_plugin_dir,
installed_plugin_dir,
node_bin_path,
plugin_runtime_main,
false,
)
.await,
);
match bootstrap::create_and_initialize_manager(
vendored_plugin_dir,
installed_plugin_dir,
node_bin_path,
plugin_runtime_main,
&query_manager,
&PluginContext::new_empty(),
false,
)
.await
{
let db = query_manager.connect();
if let Err(err) = plugin_manager.ensure_bundled_plugins_registered(&db).await {
eprintln!("Warning: Failed to register bundled plugins: {err}");
Ok(plugin_manager) => Some(plugin_manager),
Err(err) => {
eprintln!("Warning: Failed to initialize plugins: {err}");
None
}
}
let plugins = query_manager.connect().list_plugins().unwrap_or_default();
if !plugins.is_empty() {
let errors = plugin_manager
.initialize_all_plugins(plugins, &PluginContext::new_empty())
.await;
for (plugin_dir, error_msg) in errors {
eprintln!(
"Warning: Failed to initialize plugin '{}': {}",
plugin_dir, error_msg
);
}
}
Some(plugin_manager)
} else {
None
};

View File

@@ -27,7 +27,8 @@ use yaak_plugins::api::{
PluginNameVersion, PluginSearchResponse, PluginUpdatesResponse, check_plugin_updates,
search_plugins,
};
use yaak_plugins::events::{Color, Icon, PluginContext, ShowToastRequest};
use yaak_plugins::bootstrap;
use yaak_plugins::events::PluginContext;
use yaak_plugins::install::{delete_and_uninstall, download_and_install};
use yaak_plugins::manager::PluginManager;
use yaak_plugins::plugin_meta::get_plugin_meta;
@@ -267,45 +268,23 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.join("index.cjs");
let dev_mode = is_dev();
let query_manager =
app_handle.state::<yaak_models::query_manager::QueryManager>().inner().clone();
// Create plugin manager asynchronously
let app_handle_clone = app_handle.clone();
tauri::async_runtime::block_on(async move {
let manager = PluginManager::new(
let manager = bootstrap::create_and_initialize_manager(
vendored_plugin_dir,
installed_plugin_dir,
node_bin_path,
plugin_runtime_main,
&query_manager,
&PluginContext::new_empty(),
dev_mode,
)
.await;
let db = app_handle_clone.db();
manager
.ensure_bundled_plugins_registered(&db)
.await
.expect("Failed to register bundled plugins");
// Get all plugins from database and initialize
let plugins = db.list_plugins().expect("Failed to list plugins from database");
drop(db); // Explicitly drop the connection before await
let errors =
manager.initialize_all_plugins(plugins, &PluginContext::new_empty()).await;
// Show toast for any failed plugins
for (plugin_dir, error_msg) in errors {
let plugin_name = plugin_dir.split('/').last().unwrap_or(&plugin_dir);
let toast = ShowToastRequest {
message: format!("Failed to start plugin '{}': {}", plugin_name, error_msg),
color: Some(Color::Danger),
icon: Some(Icon::AlertTriangle),
timeout: Some(10000),
};
if let Err(emit_err) = app_handle_clone.emit("show_toast", toast) {
error!("Failed to emit toast for plugin error: {emit_err:?}");
}
}
.await
.expect("Failed to initialize plugins");
app_handle_clone.manage(manager);
});

View File

@@ -0,0 +1,66 @@
use crate::error::{Error, Result};
use crate::events::PluginContext;
use crate::manager::PluginManager;
use std::path::PathBuf;
use std::sync::Arc;
use yaak_models::models::Plugin;
use yaak_models::query_manager::QueryManager;
use yaak_models::util::UpdateSource;
/// Create a plugin manager and initialize all registered plugins.
///
/// This performs:
/// 1. Plugin runtime startup (`PluginManager::new`)
/// 2. Bundled plugin registration in DB (if missing)
/// 3. Plugin initialization from DB
pub async fn create_and_initialize_manager(
vendored_plugin_dir: PathBuf,
installed_plugin_dir: PathBuf,
node_bin_path: PathBuf,
plugin_runtime_main: PathBuf,
query_manager: &QueryManager,
plugin_context: &PluginContext,
dev_mode: bool,
) -> Result<Arc<PluginManager>> {
let plugin_manager = Arc::new(
PluginManager::new(
vendored_plugin_dir,
installed_plugin_dir,
node_bin_path,
plugin_runtime_main,
dev_mode,
)
.await,
);
let bundled_dirs = plugin_manager.list_bundled_plugin_dirs().await?;
let db = query_manager.connect();
for dir in bundled_dirs {
if db.get_plugin_by_directory(&dir).is_none() {
db.upsert_plugin(
&Plugin {
directory: dir,
enabled: true,
url: None,
..Default::default()
},
&UpdateSource::Background,
)?;
}
}
let plugins = db.list_plugins()?;
drop(db);
let init_errors = plugin_manager.initialize_all_plugins(plugins, plugin_context).await;
if !init_errors.is_empty() {
let joined = init_errors
.into_iter()
.map(|(dir, err)| format!("{dir}: {err}"))
.collect::<Vec<_>>()
.join("; ");
return Err(Error::PluginErr(format!("Failed to initialize plugin(s): {joined}")));
}
Ok(plugin_manager)
}

View File

@@ -7,6 +7,7 @@
//! by yaak-app's plugins_ext module.
pub mod api;
pub mod bootstrap;
mod checksum;
pub mod error;
pub mod events;

View File

@@ -33,9 +33,8 @@ use tokio::net::TcpListener;
use tokio::sync::mpsc::error::TrySendError;
use tokio::sync::{Mutex, mpsc, oneshot};
use tokio::time::{Instant, timeout};
use yaak_models::db_context::DbContext;
use yaak_models::models::Plugin;
use yaak_models::util::{UpdateSource, generate_id};
use yaak_models::util::generate_id;
use yaak_templates::error::Error::RenderError;
use yaak_templates::error::Result as TemplateResult;
@@ -181,33 +180,6 @@ impl PluginManager {
read_plugins_dir(&plugins_dir).await
}
/// Ensure all bundled plugin directories are present in the plugins table.
/// Returns a list of newly registered plugin directories.
pub async fn ensure_bundled_plugins_registered(
&self,
db: &DbContext<'_>,
) -> Result<Vec<String>> {
let bundled_dirs = self.list_bundled_plugin_dirs().await?;
let mut registered = Vec::new();
for dir in bundled_dirs {
if db.get_plugin_by_directory(&dir).is_none() {
db.upsert_plugin(
&Plugin {
directory: dir.clone(),
enabled: true,
url: None,
..Default::default()
},
&UpdateSource::Background,
)?;
registered.push(dir);
}
}
Ok(registered)
}
pub async fn uninstall(&self, plugin_context: &PluginContext, dir: &str) -> Result<()> {
let plugin = self.get_plugin_by_dir(dir).await.ok_or(PluginNotFoundErr(dir.to_string()))?;
self.remove_plugin(plugin_context, &plugin).await

View File

@@ -1,4 +1,4 @@
const { readdirSync, cpSync, existsSync } = require('node:fs');
const { readdirSync, cpSync, existsSync, mkdirSync } = require('node:fs');
const path = require('node:path');
const pluginsDir = path.join(__dirname, '..', 'plugins');
@@ -24,6 +24,7 @@ for (const name of readdirSync(pluginsDir)) {
continue;
}
const destDir = path.join(__dirname, '../crates-tauri/yaak-app/vendored/plugins/', name);
mkdirSync(destDir, { recursive: true });
console.log(`Copying ${name} to ${destDir}`);
cpSync(path.join(dir, 'package.json'), path.join(destDir, 'package.json'));
cpSync(path.join(dir, 'build'), path.join(destDir, 'build'), { recursive: true });