1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Core IPC layer for the NERVE protocol.
//!
//! `nerve-ipc-core` provides the runtime infrastructure for local NERVE
//! daemon communication: it accepts NERVE-framed binary messages from a
//! browser extension (via WebSocket) and from local tools (via Unix Domain
//! Socket), authenticates connections, dispatches frames, and manages
//! per-connection request lifecycles.
//!
//! # When to use this crate
//!
//! Use `nerve-ipc-core` when you are building a transport layer for the
//! NERVE protocol — a local daemon, a custom server, or a system-integration
//! test harness.
//!
//! If you only need to encode and decode NERVE frames without running a
//! server, use [`nerve-ipc`](https://crates.io/crates/nerve-ipc) directly.
//! `nerve-ipc-core` does not re-export any `nerve-ipc` types; you will need
//! `nerve-ipc` as a direct dependency to access types such as
//! `nerve_protocol::types::RequestId` or the codec functions.
//!
//! # Quick start
//!
//! The daemon binary starts a WebSocket server (for the browser extension) and
//! a UDS server (for local tools) concurrently:
//!
//! ```no_run
//! use nerve_ipc_core::{Config, auth};
//! use std::thread;
//!
//! fn main() -> std::io::Result<()> {
//! let config = Config::default();
//!
//! // Load the per-install secret token, creating it on first run.
//! let token = auth::load_or_create_token(&config.token_path)?;
//!
//! // Start the WebSocket server (browser extension transport) in a thread.
//! let ws_config = config.clone();
//! let ws_token = token.clone();
//! thread::spawn(move || {
//! nerve_ipc_core::ws_server::run_ws(ws_config, ws_token)
//! .expect("WebSocket server failed");
//! });
//!
//! // Start the Unix Domain Socket server (local tool transport).
//! // This call blocks until the listener is closed.
//! nerve_ipc_core::server::run(&config.uds_path)
//! }
//! ```
//!
//! # Core concepts
//!
//! ## Transports
//!
//! Two independent transports share the same dispatch logic:
//!
//! - **[`server`]** — Unix Domain Socket server for local tool integrations.
//! Entry point: [`server::run`].
//! - **[`ws_server`]** — WebSocket server on `127.0.0.1:9001` for the browser
//! extension. Entry point: [`ws_server::run_ws`]. All connections are
//! authenticated at the HTTP upgrade step via Origin check and per-install
//! token.
//!
//! Both transports call the same [`dispatch_frame`] function:
//!
//! ```text
//! Browser Extension ──WebSocket──▶ ws_server ──┐
//! ├──▶ dispatch_frame() ──▶ RequestTable
//! Local Tool ──UDS──────▶ server ──┘
//! ```
//!
//! ## Dispatch
//!
//! [`dispatch_frame`] is transport-agnostic: it reads a decoded NERVE frame,
//! updates the [`RequestTable`], and returns a [`DispatchAction`] telling the
//! transport what to do next — write a reply, forward to the AI daemon, or do
//! nothing. It performs no I/O itself.
//!
//! ## Request lifecycle
//!
//! Each accepted connection owns a [`RequestTable`] that tracks in-flight
//! requests for that connection only. A `SearchQuery` frame causes
//! [`dispatch_frame`] to insert the request and return
//! [`DispatchAction::ForwardToAiDaemon`]. A `Cancel` frame marks it
//! [`RequestState::Cancelled`]. The AI daemon checks
//! [`RequestTable::is_cancelled`] before each result and calls
//! [`RequestTable::remove`] on completion. Request IDs are scoped per
//! connection; the same ID on two different connections refers to two
//! independent requests.
//!
//! # Relationship to nerve-ipc
//!
//! | Crate | Role |
//! |---|---|
//! | [`nerve-ipc`](https://crates.io/crates/nerve-ipc) | Wire format, codec, frame types, protocol constants |
//! | `nerve-ipc-core` *(this crate)* | Authentication, request lifecycle, dispatch, UDS server, WebSocket server |
//!
//! `nerve-ipc-core` does not redefine any protocol types. All frame encoding
//! and decoding is performed by `nerve-ipc`. Types such as
//! `nerve_protocol::types::RequestId` and `nerve_protocol::Frame` come from
//! `nerve-ipc` and appear directly in this crate's public API.
pub use Config;
pub use ;
pub use ;