OXYGENHUB
# f2d2776b2a14 oxygenhub / crates / hub / src / web / help.rs
3.9 KiB · Rust · last changed Agents show on the website: seals count, the via line knows certified keys, Contributors names agents; help sets an agent's author (closes #352) 4 days ago source blame history raw
1
//! `/help` (hub spec §6.3): getting started with this hub's own address,
2
//! remote name and certificate filled in, the keyboard, and a glossary
3
//! for people coming from GitHub.
4
5
use super::repo::Quickstart;
6
use super::{Page, Shell};
7
use crate::auth::Viewer;
8
use crate::Shared;
9
use askama::Template;
10
use axum::extract::State;
11
12
#[derive(Template)]
13
#[template(path = "help.html")]
14
pub struct HelpPage {
15
    shell: Shell,
16
    q: Quickstart,
17
    base: String,
18
    /// The signed-in user, or a placeholder, for example URLs.
19
    who: String,
20
    /// What an agent's changes are authored as: the signed-in user's
21
    /// name, email and newest linked key, or placeholders (#352).
22
    author: (String, String, String),
23
}
24
25
pub async fn help(State(app): State<Shared>, viewer: Viewer) -> Page<HelpPage> {
26
    let shell = Shell::new(&app, "/help", &viewer);
27
    let who = shell.user.clone().unwrap_or_else(|| "OWNER".into());
28
    let base = app.config.base_url().trim_end_matches('/').to_string();
29
    let mut author = ("YOUR NAME".to_string(), "[email protected]".to_string(), "YOUR_KEY".to_string());
30
    if let Some(name) = &shell.user {
31
        if let Ok(Some(a)) = crate::db::accounts::account_by_name(&app.db, name).await {
32
            let newest = crate::db::accounts::identities_of(&app.db, a.id).await.ok().and_then(|ids| ids.into_iter().next());
33
            if let Some(id) = newest {
34
                author = (id.name, id.email, id.key);
35
            } else {
36
                author.0 = if a.display_name.is_empty() { a.username } else { a.display_name };
37
            }
38
        }
39
    }
40
    Page(HelpPage { shell, q: Quickstart::new(&app, true), base, who, author })
41
}
42
43
impl HelpPage {
44
    /// Trust this hub's certificate, when it is self-signed (empty otherwise).
45
    pub fn ca_setup(&self) -> String {
46
        match &self.q.ca_url {
47
            Some(url) => format!("mkdir -p ~/.config/oxy\ncurl -fsSL {url} -o {}", self.q.ca_file),
48
            None => String::new(),
49
        }
50
    }
51
52
    /// An example repository address on this hub.
53
    pub fn repo_url(&self) -> String {
54
        format!("{}/{}/REPOSITORY", self.base, self.who)
55
    }
56
57
    /// An agent's own home, keyless, with its grant kept (#287), authored
58
    /// as you with the key you make its grant with (#352): without an
59
    /// author its changes are unattributed, and a grant made by a newer key
60
    /// than its author key does not count for it.
61
    pub fn agent_home_cmd(&self) -> String {
62
        let (name, email, key) = &self.author;
63
        format!(
64
            "mkdir -p ~/.oxy-agents/claude/keys\n\
65
             oxy identity export ~/.oxy-agents/claude/keys/{key}.identity   # in a checkout of yours, as you\n\
66
             export OXY_HOME=~/.oxy-agents/claude\n\
67
             oxy config --user author.name \"{name}\"\n\
68
             oxy config --user author.email \"{email}\"\n\
69
             oxy config --user author.key {key}\n\
70
             oxy config --user author.signer keyless\n\
71
             oxy config --user keyless.hub {base}\n\
72
             oxy config --user core.sign seal\n\
73
             oxy auth grant {base}   # paste the token, then Ctrl-D",
74
            base = self.base
75
        )
76
    }
77
78
    /// A repository's trust policy admitting an agent's certified keys (#287).
79
    pub fn subject_grant_cmd(&self) -> String {
80
        format!(
81
            "curl -fsSL {}/.well-known/oxyhub-key -o hub.identity\noxy policy grant-subject agent:claude@{} --issuer hub.identity --scope changes,refs",
82
            self.base, self.who
83
        )
84
    }
85
86
    pub fn delegate_cmd(&self) -> String {
87
        format!(
88
            "curl -fsSL {}/.well-known/oxyhub-key -o hub.identity\noxy identity delegate add hub.identity --scope changes,refs",
89
            self.base
90
        )
91
    }
92
93
    pub fn clone_cmd(&self) -> String {
94
        let url = self.repo_url();
95
        match &self.q.ca_url {
96
            Some(_) => format!("OXY_CA={} oxy clone {url}", self.q.ca_file),
97
            None => format!("oxy clone {url}"),
98
        }
99
    }
100
}