Plugins

Covers Engine Plugin SDK 2.0.0 · Interface Plugin SDK 0.2.0

pluginWorkspaceAssetPath

Portable assets/plugins/id/relative reference for authored shared plugin files. Bind the manifest's plugin ID. Validates segments and requires a file extension. No I/O or isolation from generic storage APIs.

Declaration

inline std::string pluginWorkspaceAssetPath(const std::string& plugin_id, const std::string& relative) {
        workspaceAssetPath(plugin_id, "validation.json");
        const std::filesystem::path path(relative);
        if (path.is_absolute() || path.has_root_name() || relative.empty() || relative.find('\\') != std::string::npos)
            throw std::invalid_argument("Plugin asset files must be relative paths.");
        for (const auto& part : path) workspaceAssetPath(part.string(), "validation.json");
        workspaceAssetPath(plugin_id, path.filename().string());
        return "assets/plugins/" + plugin_id + "/" + relative;
    }
    using Transport = TEMPEST::Transport;
    using TransportPtr = std::shared_ptr<TEMPEST::Transport>;
    enum class TaskStructure {
        Unknown,
        Periodic,
        StateMachine,
        Sequence,
        Timeline,
        Worker
    };
    enum class ChannelField {
        VALUE,
        COMMANDED_BY,
        TIMESTAMP,
        UNITS,
        STALE_TIMEOUT,
        RECORD_MODE,
        CONTROL_POLICY,
        CONTROL_OWNER,
        ACTIVE_CONTROLLER,
        LINKED_CALCULATION_SCRIPTS,
        VALUE_OPTIONS,
        STARTUP_VALUE
    };
    enum class RecordMode {
        OnValueChange,
        Never,
        EveryValue,
        EveryValueExcludeAutorecord
    };
    enum class ControlPolicy {
        Free,
        Automatic,
        ManualOverride,
        ObserveOnly
    };

    struct ChannelValueOption {
        double value = 0.0;
        std::string label;
    };

    struct ChannelCalculationLink {
        std::string script;
        std::string relationship;
        uint32_t line_number = 0;
    };

    struct StartupValue {
        bool enabled = false;
        double value = 0.0;
    };

    enum class ChannelStorage {
        Dynamic,
        Fixed
    };
    struct FixedChannelHandle {
        uint32_t slot = 0;
        uint64_t binding_generation = 0;
        std::shared_ptr<const std::string> channel;
        const void* owner = nullptr;

        [[nodiscard]] bool valid() const noexcept {
            return binding_generation != 0 && channel && owner;
        }
    };
    using ChannelValue = std::variant<double, int, std::string, bool, RecordMode, ControlPolicy,
        std::vector<ChannelValueOption>, std::vector<ChannelCalculationLink>, StartupValue>;
    using OperationHandler = std::function<nlohmann::json(const nlohmann::json& payload)>;
    struct OperationArgumentDefinition {
        std::string name;
        std::string type;
        std::string description;
        bool required = false;
        std::optional<nlohmann::json> default_value;
        std::vector<nlohmann::json> choices;
    };
    struct OperationDefinition {
        std::string id;
        std::string name;
        std::string description;
        std::string category;
        std::vector<OperationArgumentDefinition> arguments;
        OperationHandler handler;
        bool allow_viewers = false;
    };
    struct TelemetryDefinition {
        std::string id;
        std::string name;
        std::string description;
        std::string delivery;
    };
    using DCodeFunctionHandler = std::function<nlohmann::json(nlohmann::json& payload)>;
    using DCodePreparedFunctionHandler = std::function<void(
        DCodePreparedValueView& input, DCodePreparedMutableValue& result)>;
    struct DCodeFunctionArgument {
        std::string name;
        std::string type;
        std::string doc;
        bool required = false;
        // Fixed list size and named dictionary fields are used by prepared
        // native calls; ordinary Lua values may still grow when unshaped.
        std::optional<size_t> list_length;
        std::shared_ptr<DCodeFunctionArgument> element;
        std::vector<DCodeFunctionArgument> fields;
    };

    struct TaskTypeDefinition;
    struct TaskTypeMetadata {
        std::string task_type;
        TaskStructure structure = TaskStructure::Unknown;
        std::string icon_url;
        std::string exposed_from;
        std::string expected_plugin_id;
        nlohmann::json default_arguments = nlohmann::json::object();
    };
    class TaskRuntime {
    public:
        virtual ~TaskRuntime() = default;

        virtual const std::string& getTaskName() const = 0;
        virtual const std::string& getTaskType() const = 0;
        virtual const nlohmann::json& getMetadata() const = 0;
        virtual const nlohmann::json& getArguments() const = 0;
        virtual double getElapsedSeconds() const = 0;
        virtual bool isStopRequested() const = 0;

        virtual void setRuntimeContext(const std::string& key, std::shared_ptr<void> value) = 0;
        virtual std::shared_ptr<void> getRuntimeContext(const std::string& key) const = 0;
        virtual void removeRuntimeContext(const std::string& key) = 0;
        virtual void clearRuntimeContext() = 0;
        // Keep new virtual functions appended so plugins built against the previous
        // TaskRuntime vtable retain the indices of all existing functions.
        virtual void setFixedInputChannels(std::vector<std::string> channels) = 0;
        virtual void recordWorkerCycle() = 0;

        template <typename T>
        void setTypedRuntimeContext(const std::string& key, const std::shared_ptr<T>& value) {
            setRuntimeContext(key, std::static_pointer_cast<void>(value));
        }

        template <typename T>
        std::shared_ptr<T> getTypedRuntimeContext(const std::string& key) const {
            return std::static_pointer_cast<T>(getRuntimeContext(key));
        }
    }