Compare commits

...

2 Commits

Author SHA1 Message Date
Ian Chua
4c2d9b4b18 Merge branch 'main' into fix/plugin-install-state 2026-07-21 12:55:30 +08:00
Ian Chua
28feb8480e fix: reserve plugin enable state during rescans 2026-07-20 18:40:31 +08:00
4 changed files with 15 additions and 7 deletions

View File

@@ -66,6 +66,10 @@ struct PluginDescriptor
std::string error; // Blocking error message. Non-empty means the plugin is in an error state.
std::optional<CloudPluginState> cloud; // Extra cloud state layered on top of a normal plugin descriptor.
bool metadata_valid = false; // Manifest/package validity stays separate from the user-facing error field.
// Whether the discovery pass successfully read .install_state.json. This is transient scan
// metadata, used to distinguish an explicit enabled=false from a sidecar that was unavailable
// during a live package replacement.
bool install_state_valid = false;
// Package auto-load flag, read from .install_state.json. Defaults to FALSE: a package with no
// sidecar has never been installed through Orca and carries no auto-load intent, so it must not
// be loaded at startup. Installing a package writes the sidecar with enabled = true.

View File

@@ -172,7 +172,7 @@ void scan_plugin_directory(const std::string& dir_path, std::vector<PluginDescri
// its error, rather than dropping it silently.
if (entry_path.empty()) {
descriptor.set_error(entry_error);
read_install_state(plugin_dir, descriptor);
descriptor.install_state_valid = read_install_state(plugin_dir, descriptor);
assign_discovered_plugin_key(descriptor, plugin_dir);
out.push_back(std::move(descriptor));
BOOST_LOG_TRIVIAL(warning) << "Invalid plugin package: " << plugin_dir.string() << " - " << out.back().error;
@@ -185,7 +185,7 @@ void scan_plugin_directory(const std::string& dir_path, std::vector<PluginDescri
read_python_plugin_metadata(entry_path, descriptor, meta_error);
if (!parsed) {
descriptor.set_error(meta_error);
read_install_state(plugin_dir, descriptor);
descriptor.install_state_valid = read_install_state(plugin_dir, descriptor);
assign_discovered_plugin_key(descriptor, entry_path);
out.push_back(std::move(descriptor));
BOOST_LOG_TRIVIAL(warning) << (is_wheel ? "Invalid wheel plugin: " : "Invalid .py plugin: ")
@@ -199,7 +199,7 @@ void scan_plugin_directory(const std::string& dir_path, std::vector<PluginDescri
// Cloud identity and the package-level auto-load flag. plugin_key is always derived
// below, never read from the sidecar.
read_install_state(plugin_dir, descriptor);
descriptor.install_state_valid = read_install_state(plugin_dir, descriptor);
assign_discovered_plugin_key(descriptor, entry_path);
out.push_back(std::move(descriptor));
@@ -735,11 +735,11 @@ bool extract_zip_to_directory(const boost::filesystem::path& zip_path, const boo
return true;
}
void read_install_state(const boost::filesystem::path& plugin_dir, PluginDescriptor& entry)
bool read_install_state(const boost::filesystem::path& plugin_dir, PluginDescriptor& entry)
{
PluginInstallState state;
if (!read_install_state(plugin_dir, state))
return;
return false;
// The cloud identity and the persisted installed version are read back. plugin_key
// is always derived by the catalog scan (filename for local, the cloud uuid for
@@ -756,6 +756,7 @@ void read_install_state(const boost::filesystem::path& plugin_dir, PluginDescrip
// capability has no existence — and so no state — until it is materialized, at which point the
// loader seeds the flag onto the capability itself.
entry.enabled = state.enabled;
return true;
}
bool read_install_state(const boost::filesystem::path& plugin_dir, PluginInstallState& out)

View File

@@ -156,8 +156,9 @@ bool write_install_state(const boost::filesystem::path& plugin_dir, const Plugin
// Convenience overload: write(dir, entry, /*enabled=*/true, /*capabilities=*/{}).
bool write_install_state(const boost::filesystem::path& plugin_dir, const PluginDescriptor& entry);
// Reads only the cloud identity (uuid) back into the descriptor; plugin_key is always derived.
void read_install_state(const boost::filesystem::path& plugin_dir, PluginDescriptor& entry);
// Reads install state back into the descriptor; plugin_key is always derived. Returns whether the
// sidecar was present and valid.
bool read_install_state(const boost::filesystem::path& plugin_dir, PluginDescriptor& entry);
// Full read of the sidecar; returns false if there is no/invalid sidecar.
bool read_install_state(const boost::filesystem::path& plugin_dir, PluginInstallState& out);

View File

@@ -321,6 +321,8 @@ void PluginManager::merge_discovered_plugins(std::vector<PluginDescriptor> disco
// A manifest-only rescan has nothing to say about capabilities, so the live module and
// instances are left alone.
if (!descriptor.install_state_valid)
descriptor.enabled = existing->descriptor.enabled;
existing->descriptor = std::move(descriptor);
}