Skip to main content

forge_server/surface/
plugins.rs

1//! `plugins()`: the plugin inventory and update records.
2
3use forge_primitives::plugins::PluginUpdateRecord;
4
5use super::ViewSurface;
6
7/// The plugin inventory and its update records.
8pub struct PluginsView {
9    /// Every remembered plugin update, latest write per installed entry.
10    pub update_records: Vec<PluginUpdateRecord>,
11}
12
13impl ViewSurface {
14    pub fn plugins(&self) -> PluginsView {
15        PluginsView { update_records: self.workspace.plugin_update_records() }
16    }
17}
18
19#[cfg(test)]
20mod tests {
21    use std::sync::Arc;
22
23    use forge_primitives::plugins::{PluginUpdateRecord, PluginUpdateTrigger};
24
25    use super::*;
26
27    /// Catches the verb being pointed at a different store row than the
28    /// call it replaces, which would render stale or empty update
29    /// records in the Extensions pane.
30    #[test]
31    fn plugins_agrees_with_the_call_it_replaces() {
32        let (workspace, _dir) = crate::surface::testing::workspace();
33        let record = PluginUpdateRecord {
34            plugin_id: "night-market".to_owned(),
35            marketplace: "abstract".to_owned(),
36            scope: "user".to_owned(),
37            cwd_raw: String::new(),
38            from_version: Some("1.0.0".to_owned()),
39            to_version: Some("2.0.0".to_owned()),
40            marketplace_ref_before: Some("abc123".to_owned()),
41            updated_at: "2026-09-25T00:00:00Z".to_owned(),
42            trigger: PluginUpdateTrigger::Manual,
43        };
44        workspace.record_plugin_updates(std::slice::from_ref(&record));
45
46        let view = ViewSurface::new(Arc::clone(&workspace)).plugins();
47
48        assert_eq!(
49            view.update_records,
50            workspace.plugin_update_records(),
51            "the records are the call's own",
52        );
53        assert_eq!(view.update_records, vec![record], "the seeded record is what the read returns");
54    }
55}