Skip to main content

warble_claude_code/
manifest.rs

1//! Capability manifest emitter.
2//!
3//! The manifest is the runtime-agnostic **interop surface** a meta-harness consumes to decide
4//! whether it can call a Warble profile and what it needs — without absorbing execution (see
5//! [`capability-model.md`][spec-cap]). It is a pure projection of the IR: verbs, context, required
6//! capabilities, render contract. Distinct from `resolve.rs`, which links required capabilities
7//! against a *specific* target.
8//!
9//! [spec-cap]: https://github.com/Canner/Warble/blob/main/docs/spec/capability-model.md
10
11use crate::ir::{ComponentNode, WarbleIr};
12use serde::Serialize;
13
14pub const MANIFEST_VERSION: &str = "0.1";
15
16#[derive(Debug, Serialize)]
17pub struct RenderContract {
18    pub blocks: Vec<String>,
19}
20
21#[derive(Debug, Serialize)]
22pub struct ManifestContext {
23    pub project: String,
24    pub binding_mode: String,
25    pub precondition: String,
26}
27
28#[derive(Debug, Serialize)]
29pub struct ManifestComponent {
30    pub verb: String,
31    #[serde(rename = "type")]
32    pub component_type: String,
33    pub realization_kind: String,
34    pub context: ManifestContext,
35    pub trigger: String,
36    pub outcome: String,
37    pub required_capabilities: Vec<String>,
38    /// Declared render block types, or null when the component renders nothing.
39    pub render_contract: Option<RenderContract>,
40}
41
42#[derive(Debug, Serialize)]
43pub struct CapabilityManifest {
44    pub warble_manifest_version: String,
45    pub profile: String,
46    pub components: Vec<ManifestComponent>,
47}
48
49fn manifest_component(node: &ComponentNode) -> ManifestComponent {
50    let block_types: Vec<String> = node
51        .effect
52        .render_blocks
53        .iter()
54        .map(|b| b.block_type.clone())
55        .collect();
56    ManifestComponent {
57        verb: node.verb.clone(),
58        component_type: node.component_type.as_str().to_string(),
59        realization_kind: node.realization_kind.as_str().to_string(),
60        context: ManifestContext {
61            project: node.context_binding.project.clone(),
62            binding_mode: node.context_binding.binding_mode.clone(),
63            precondition: node.precondition_result.status.clone(),
64        },
65        trigger: node.trigger.kind.as_str().to_string(),
66        outcome: node.effect.outcome.kind.as_str().to_string(),
67        required_capabilities: node.required_capabilities.clone(),
68        render_contract: if block_types.is_empty() {
69            None
70        } else {
71            Some(RenderContract {
72                blocks: block_types,
73            })
74        },
75    }
76}
77
78/// Project a resolved IR into its runtime-agnostic capability manifest.
79pub fn build_manifest(ir: &WarbleIr) -> CapabilityManifest {
80    CapabilityManifest {
81        warble_manifest_version: MANIFEST_VERSION.to_string(),
82        profile: ir.profile.clone(),
83        components: ir.components.iter().map(manifest_component).collect(),
84    }
85}