Files
optimclaw/src/channels/wasm/mod.rs
T
94d101924e refactor: encapsulate leaked abstractions into owning modules (#778)
* refactor: encapsulate leaked abstractions from main.rs and app.rs into owning modules

Move module-specific initialization logic out of main.rs (1222→665 lines, -46%) and
app.rs (944→780 lines, -17%) into their respective owning modules as public factory
functions. This enforces separation of concerns so that adding a new DB backend, MCP
transport, or channel doesn't require editing main.rs/app.rs.

Key changes:
- Tracing init functions → src/tracing_fmt.rs
- DB connection factory (connect_with_handles + DatabaseHandles) → src/db/mod.rs
- Secrets store factory (create_secrets_store) → src/secrets/mod.rs
- MCP transport dispatch factory (create_client_from_config) → src/tools/mcp/factory.rs
- Orchestrator setup (setup_orchestrator + OrchestratorSetup) → src/orchestrator/mod.rs
- WASM channel setup (setup_wasm_channels) → src/channels/wasm/setup.rs
- Worker entry points (run_worker, run_claude_bridge) → src/worker/mod.rs
- Shared CLI secrets init (init_secrets_store) → src/cli/mod.rs
- Tunnel startup (start_managed_tunnel) → src/tunnel/mod.rs
- Onboard check (check_onboard_needed) → src/setup/mod.rs
- ExtensionManager unified MCP: uses create_client_from_config via McpProcessManager,
  enabling stdio/Unix transports for hot-activated MCP servers
- Deduplicated ~130 lines of secrets store init across cli/mcp.rs and cli/tool.rs
- CLAUDE.md updated with module-owned initialization guideline

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: address review feedback — deduplicate db factory, extract channel helper

- connect_from_config() now delegates to connect_with_handles() to eliminate
  duplicated backend-matching logic (Copilot review feedback)
- Extract register_channel() helper from setup_wasm_channels() loop body
  to improve readability (Gemini review feedback)

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* style: fix rustfmt line wrapping in setup_wasm_channels

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* test: add integration test for module-owned initialization factories

Exercises the full factory chain end-to-end to verify nothing was lost
when initialization logic was moved from main.rs/app.rs into owning modules:

- connect_with_handles returns Database + populated backend handles
- connect_from_config delegates correctly (produces working Database)
- secrets::create_secrets_store builds working store from DatabaseHandles
- db::create_secrets_store standalone factory round-trips secrets
- Both secrets factories produce compatible stores (cross-read works)
- ExtensionManager constructs with McpProcessManager and is functional
- DatabaseHandles default is empty

All tests run without external services using libsql in-memory/tempfile.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: wire cli/mcp.rs and cli/tool.rs to shared init_secrets_store()

Both files had inline implementations identical to cli::init_secrets_store().
Replace with delegation to complete the claimed deduplication.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* style: fix rustfmt line wrapping in integration test

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(review): remove unused Config import and deduplicate Error Handling section

- Remove `#[allow(unused_imports)]` and unused `use crate::config::Config`
  from cli/tool.rs (no longer needed after delegating to shared
  `cli::init_secrets_store()`)
- Remove duplicate Error Handling subsection from CLAUDE.md Key Patterns
  (all four bullets already exist in Code Style section and
  review-discipline.md)

Addresses Copilot review comments.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(review): address remaining Copilot review comments

- secrets/mod.rs: clarify docstring that None is a normal no-db condition
- app.rs: add comment explaining the empty_handles fallback path
- orchestrator/mod.rs: combine duplicated sandbox condition into single block
- setup/mod.rs: document env var reads and thread-safety caveat

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Henry Park <[email protected]>
2026-03-10 04:39:51 +00:00

111 lines
6.7 KiB
Rust

//! WASM-extensible channel system.
//!
//! This module provides a runtime for executing WASM-based channels using a
//! Host-Managed Event Loop pattern. The host (Rust) manages infrastructure
//! (HTTP server, polling), while WASM modules define channel behavior through
//! callbacks.
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────────────────────┐
//! │ Host-Managed Event Loop │
//! │ │
//! │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
//! │ │ HTTP │ │ Polling │ │ Timer │ │
//! │ │ Router │ │ Scheduler │ │ Scheduler │ │
//! │ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │
//! │ │ │ │ │
//! │ └───────────────────┴────────────────────┘ │
//! │ │ │
//! │ ▼ │
//! │ ┌─────────────────┐ │
//! │ │ Event Router │ │
//! │ └────────┬────────┘ │
//! │ │ │
//! │ ┌──────────────────┼──────────────────┐ │
//! │ ▼ ▼ ▼ │
//! │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
//! │ │ on_http_req │ │ on_poll │ │ on_respond │ WASM Exports │
//! │ └─────────────┘ └─────────────┘ └─────────────┘ │
//! │ │ │ │ │
//! │ └──────────────────┴──────────────────┘ │
//! │ │ │
//! │ ▼ │
//! │ ┌─────────────────┐ │
//! │ │ Host Imports │ │
//! │ │ emit_message │──────────▶ MessageStream │
//! │ │ http_request │ │
//! │ │ log, etc. │ │
//! │ └─────────────────┘ │
//! └─────────────────────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Key Design Decisions
//!
//! 1. **Fresh Instance Per Callback** (NEAR Pattern) - Full isolation, no shared mutable state
//! 2. **Host Manages Infrastructure** - HTTP server, polling, timing in Rust
//! 3. **WASM Defines Behavior** - Callbacks for events, message parsing, response handling
//! 4. **Reuse Tool Runtime** - Share Wasmtime engine, extend capabilities
//!
//! # Security Model
//!
//! | Threat | Mitigation |
//! |--------|------------|
//! | Path hijacking | `allowed_paths` restricts registrable endpoints |
//! | Token exposure | Injected at host boundary, WASM never sees |
//! | State pollution | Fresh instance per callback |
//! | Workspace escape | Paths prefixed with `channels/<name>/` |
//! | Message spam | Rate limiting on `emit_message` |
//! | Resource exhaustion | Fuel metering, memory limits, callback timeout |
//! | Polling abuse | Minimum 30s interval enforced |
//!
//! # Example Usage
//!
//! ```ignore
//! use ironclaw::channels::wasm::{WasmChannelLoader, WasmChannelRuntime};
//!
//! // Create runtime (can share engine with tool runtime)
//! let runtime = WasmChannelRuntime::new(config)?;
//!
//! // Load channels from directory
//! let loader = WasmChannelLoader::new(runtime);
//! let channels = loader.load_from_dir(Path::new("~/.ironclaw/channels/")).await?;
//!
//! // Add to channel manager
//! for channel in channels {
//! manager.add(Box::new(channel));
//! }
//! ```
mod bundled;
mod capabilities;
mod error;
mod host;
mod loader;
mod router;
mod runtime;
mod schema;
pub mod setup;
pub(crate) mod signature;
#[allow(dead_code)]
pub(crate) mod storage;
mod wrapper;
// Core types
pub use bundled::{available_channel_names, bundled_channel_names, install_bundled_channel};
pub use capabilities::{ChannelCapabilities, EmitRateLimitConfig, HttpEndpointConfig, PollConfig};
pub use error::WasmChannelError;
pub use host::{ChannelEmitRateLimiter, ChannelHostState, EmittedMessage};
pub use loader::{
DiscoveredChannel, LoadResults, LoadedChannel, WasmChannelLoader, default_channels_dir,
discover_channels,
};
pub use router::{RegisteredEndpoint, WasmChannelRouter, create_wasm_channel_router};
pub use runtime::{PreparedChannelModule, WasmChannelRuntime, WasmChannelRuntimeConfig};
pub use schema::{
ChannelCapabilitiesFile, ChannelConfig, SecretSetupSchema, SetupSchema, WebhookSchema,
};
pub use setup::{WasmChannelSetup, inject_channel_credentials, setup_wasm_channels};
pub use wrapper::{HttpResponse, SharedWasmChannel, WasmChannel};