OXYGENHUB
# 01320eefd505 spectra / crates / spectra-api / src / lib.rs
6.1 KiB · Rust · last changed The command line from another machine: every command through the API (#23, completes #21) 1 day ago source blame history raw
1
//! The JSON API's types (spec §18), with serde and JSON Schema derives, as
2
//! `hub-api` is for OxygenHub. `make ts` writes `ts/index.d.ts` from them
3
//! for spectra-vscode and spectrahub-vscode, so the extensions can never
4
//! drift from the server.
5
6
use schemars::JsonSchema;
7
use serde::{Deserialize, Serialize};
8
9
/// An error, as RFC 7807 has it.
10
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
11
pub struct Problem {
12
    #[serde(rename = "type")]
13
    pub kind: String,
14
    pub title: String,
15
    pub status: u16,
16
    #[serde(skip_serializing_if = "Option::is_none")]
17
    pub detail: Option<String>,
18
}
19
20
/// `GET /api/v1/version`.
21
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
22
pub struct Version {
23
    pub version: String,
24
    pub ledger_format: u32,
25
    pub mcp_protocol_versions: Vec<String>,
26
}
27
28
/// An agent and its owner (spec §8.1).
29
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
30
pub struct Agent {
31
    pub name: String,
32
    /// `claude-oxygen · Andy McCall's agent`.
33
    pub display: String,
34
    pub owner: String,
35
    pub key: String,
36
    pub kind: String,
37
    pub project: String,
38
    /// online, busy, idle, blocked, paused or offline.
39
    pub presence: String,
40
    pub status: Option<String>,
41
    pub disabled: bool,
42
    /// `ok` while the owner's identity delegates to the key, else why not.
43
    #[serde(default)]
44
    pub state: String,
45
    /// When the owner's delegation to the key ends, in ms.
46
    #[serde(default)]
47
    pub delegation_expires: Option<u64>,
48
}
49
50
/// A project (spec §23.1).
51
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
52
pub struct Project {
53
    pub name: String,
54
    pub path: String,
55
    pub remote: Option<String>,
56
    pub depends_on: Vec<String>,
57
    pub depended_on_by: Vec<String>,
58
    /// Its agents that are not disabled.
59
    #[serde(default)]
60
    pub agents: Vec<String>,
61
}
62
63
/// A channel (spec §10.1).
64
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
65
pub struct Channel {
66
    pub id: String,
67
    pub name: String,
68
    /// `#general`, `#oxygen`, or `@a+b` for a direct channel.
69
    pub display: String,
70
    pub kind: String,
71
    pub purpose: Option<String>,
72
    pub messages: i64,
73
}
74
75
/// A message (spec §10.3); a redacted one's body says so.
76
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
77
pub struct Message {
78
    pub id: String,
79
    pub channel: String,
80
    pub reply_to: Option<String>,
81
    pub author: String,
82
    pub author_display: String,
83
    pub kind: String,
84
    pub body: String,
85
    pub mentions: Vec<String>,
86
    pub refs: Vec<String>,
87
    pub at_ms: i64,
88
    pub replies: i64,
89
    pub redacted: bool,
90
}
91
92
/// A page of messages, oldest first; `next` is the cursor for the next page.
93
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
94
pub struct Messages {
95
    pub channel: String,
96
    pub items: Vec<Message>,
97
    pub next: Option<String>,
98
}
99
100
/// `POST /api/v1/channels/{name}/messages`.
101
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
102
pub struct NewMessage {
103
    pub body: String,
104
    #[serde(default)]
105
    pub reply_to: Option<String>,
106
    #[serde(default)]
107
    pub kind: Option<String>,
108
}
109
110
/// What a post did.
111
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
112
pub struct Posted {
113
    pub id: String,
114
    pub channel: String,
115
    /// True when it was dropped as a repeat of `id` within a minute.
116
    pub duplicate: bool,
117
}
118
119
/// An unread mention or direct message (spec §14.5).
120
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
121
pub struct InboxItem {
122
    pub id: String,
123
    pub kind: String,
124
    pub at_ms: i64,
125
    pub from: String,
126
    /// `claude-oxygen · Andy McCall's agent`, or the human's name.
127
    #[serde(default)]
128
    pub from_display: String,
129
    pub channel: String,
130
    pub summary: String,
131
}
132
133
/// `POST /api/v1/inbox/ack`.
134
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
135
pub struct Ack {
136
    pub ids: Vec<String>,
137
    #[serde(default)]
138
    pub reaction: Option<String>,
139
}
140
141
/// A search hit (spec §13.1).
142
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
143
pub struct Hit {
144
    pub id: String,
145
    pub channel: String,
146
    pub author: String,
147
    pub at_ms: i64,
148
    pub snippet: String,
149
    pub thread: Option<String>,
150
    #[serde(default)]
151
    pub author_display: String,
152
}
153
154
/// An event as the log and the stream show it: never its payload's data on
155
/// the stream, which says only what changed (spec §17.3).
156
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
157
pub struct EventSummary {
158
    pub seq: u64,
159
    pub id: String,
160
    pub at_ms: u64,
161
    pub kind: String,
162
    pub actor: String,
163
    pub subject: Option<String>,
164
    /// system, token, signature, passkey or session.
165
    pub method: String,
166
    pub assurance: u8,
167
    pub hash: String,
168
}
169
170
/// A page of the log, oldest first.
171
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
172
pub struct Events {
173
    pub items: Vec<EventSummary>,
174
    pub next: Option<u64>,
175
}
176
177
/// `GET /api/v1/brief`: who the caller is and what is waiting.
178
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
179
pub struct Brief {
180
    pub you: String,
181
    pub actor: String,
182
    pub project: Option<String>,
183
    pub rules_version: String,
184
    pub unread: i64,
185
    pub inbox: Vec<InboxItem>,
186
    pub agents: Vec<Agent>,
187
    pub head: u64,
188
}
189
190
/// Every type, with its schema, for `make ts`.
191
pub fn schemas() -> Vec<(&'static str, schemars::Schema)> {
192
    vec![
193
        ("Problem", schemars::schema_for!(Problem)),
194
        ("Version", schemars::schema_for!(Version)),
195
        ("Agent", schemars::schema_for!(Agent)),
196
        ("Project", schemars::schema_for!(Project)),
197
        ("Channel", schemars::schema_for!(Channel)),
198
        ("Message", schemars::schema_for!(Message)),
199
        ("Messages", schemars::schema_for!(Messages)),
200
        ("NewMessage", schemars::schema_for!(NewMessage)),
201
        ("Posted", schemars::schema_for!(Posted)),
202
        ("InboxItem", schemars::schema_for!(InboxItem)),
203
        ("Ack", schemars::schema_for!(Ack)),
204
        ("Hit", schemars::schema_for!(Hit)),
205
        ("EventSummary", schemars::schema_for!(EventSummary)),
206
        ("Events", schemars::schema_for!(Events)),
207
        ("Brief", schemars::schema_for!(Brief)),
208
    ]
209
}