Skip to content
152 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a8385d293d42c913a'1/// The site's own routes: first path segments that are never a workspace's,
2/// so nobody may register them, and no alias can be reached at them.
3const ROUTES: &[&str] = &[
Workspaces own repositories4 "api",
5 "mcp",
6 "login",
7 "logout",
8 "register",
9 "new",
10 "settings",
11 "search",
12 "admin",
13 "auth",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look14 // g1t.sh/integrations/github/setup: where GitHub returns after an install.
15 "integrations",
Issues and pull requests replace intents and attempts16 "pulls",
17 "issues",
Workspaces own repositories18 "oauth",
19 "assets",
Workspace names and icons, and a component kit for every control20 "avatars",
Workspaces own repositories21 "docs",
22 "explore",
23 "about",
24 "pricing",
25 "terms",
26 "privacy",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look27 "policies",
28 "security",
Workspaces own repositories29 "help",
30 "support",
31 "status",
32 "blog",
33 "verify",
Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036)34 "confirm-email",
Workspaces own repositories35 "forgot",
36 "reset",
37 "device",
38 "workspaces",
39 "u",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look40 // g1t.sh/invite/<code>: invite links; and the waitlist.
41 "invite",
42 "invites",
43 "waitlist",
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member44 // g1t.sh/v2/: the container registry; `-` paths hold the others.
45 "v2",
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all46 // g1t.sh/inbox, and the name it might also go by.
47 "inbox",
48 "notifications",
API and MCP server, Rust identity service, registration, site redesign49];
50
Merge branch 'worktree-agent-a8385d293d42c913a'51/// g1t itself, and the name its agent once went by: everything g1t does is
52/// shown as `g1t`, so nobody else may be called either. Not routes: staff
53/// may point one at a workspace as an alias (identity's `aliases.rs`).
54const OWN: &[&str] = &["g1t", "g1t-agent"];
55
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent56/// Whether `value`, whatever its case, is a name nobody can register or
57/// rename a workspace to: a route, or g1t's own.
58pub fn is_reserved_name(value: &str) -> bool {
Merge branch 'worktree-agent-a8385d293d42c913a'59 is_route_name(value) || OWN.iter().any(|own| own.eq_ignore_ascii_case(value.trim()))
60}
61
62/// Whether `value`, whatever its case, is one of the site's own routes.
63pub fn is_route_name(value: &str) -> bool {
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent64 let value = value.trim();
Merge branch 'worktree-agent-a8385d293d42c913a'65 ROUTES.iter().any(|route| route.eq_ignore_ascii_case(value))
66}
67
68/// Whether `value` has a namespace's shape: letters, digits and single
69/// hyphens, not starting or ending with a hyphen, at most 39 characters.
70/// Reserved names have it too; see [`is_valid_namespace`].
71pub fn is_namespace_shaped(value: &str) -> bool {
72 let bytes = value.as_bytes();
73 !bytes.is_empty()
74 && bytes.len() <= 39
75 && bytes
76 .iter()
77 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || *byte == b'-')
78 && !value.starts_with('-')
79 && !value.ends_with('-')
80 && !value.contains("--")
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent81}
82
Merge branch 'worktree-agent-a8385d293d42c913a'83/// A workspace alias as staff typed it, trimmed and lowercased, if it can
84/// be one: shaped like a namespace and not one of the site's routes, which
85/// would always answer first. Reserved names such as `g1t` can be; whether
86/// a person or workspace already has it is identity's to check.
87pub fn aliasable_name(value: &str) -> Option<String> {
88 let value = value.trim().to_lowercase();
89 (is_namespace_shaped(&value) && !is_route_name(&value)).then_some(value)
90}
91
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent92/// A username or workspace slug as someone typed it, trimmed and
93/// lowercased, if it can be registered: what signing up, signing up with
94/// GitHub and creating a workspace each take. None when it is malformed or
95/// reserved.
96pub fn claimable_namespace(value: &str) -> Option<String> {
97 let value = value.trim().to_lowercase();
98 is_valid_namespace(&value).then_some(value)
99}
100
API and MCP server, Rust identity service, registration, site redesign101/// Namespaces follow GitHub's rules: letters, digits and single hyphens,
102/// not starting or ending with a hyphen, at most 39 characters.
103pub fn is_valid_namespace(value: &str) -> bool {
Merge branch 'worktree-agent-a8385d293d42c913a'104 is_namespace_shaped(value) && !is_reserved_name(value)
API and MCP server, Rust identity service, registration, site redesign105}
106
107pub fn is_valid_repo_name(value: &str) -> bool {
108 !value.is_empty()
109 && value.len() <= 100
110 && value.bytes().all(|byte| {
111 byte.is_ascii_lowercase() || byte.is_ascii_digit() || matches!(byte, b'.' | b'_' | b'-')
112 })
113 && !value.starts_with('.')
114 && !value.ends_with(".git")
Agents as a team: lifecycle, merge queue, billing and a new shell115 // `/<workspace>/-/…` holds the workspace's own pages.
116 && value != "-"
API and MCP server, Rust identity service, registration, site redesign117}
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn g1ts_own_names_are_reserved_in_any_case() {
125 for name in ["g1t", "G1T", "g1t-agent", "G1T-Agent", " g1t "] {
126 assert!(is_reserved_name(name), "{name}");
127 assert_eq!(claimable_namespace(name), None, "{name}");
128 }
129 assert!(!is_valid_namespace("g1t"));
130 assert!(!is_valid_namespace("g1t-agent"));
131 }
132
133 #[test]
134 fn names_near_g1ts_are_anyones() {
135 assert!(!is_reserved_name("g1t-agents"));
136 assert_eq!(claimable_namespace("G1T-Bot").as_deref(), Some("g1t-bot"));
137 assert_eq!(claimable_namespace(" Ana ").as_deref(), Some("ana"));
138 assert_eq!(claimable_namespace("an--a"), None);
139 }
Merge branch 'worktree-agent-a8385d293d42c913a'140
141 #[test]
142 fn g1t_can_be_an_alias_but_a_route_cannot() {
143 assert_eq!(aliasable_name(" G1T ").as_deref(), Some("g1t"));
144 assert_eq!(aliasable_name("acme-corp").as_deref(), Some("acme-corp"));
145 for name in ["settings", "api", "login", "Explore", "-acme", "ac--me", "acme_inc", "", "a.b"] {
146 assert_eq!(aliasable_name(name), None, "{name}");
147 }
148 assert_eq!(aliasable_name(&"a".repeat(40)), None);
149 // Still nobody's to register.
150 assert!(is_reserved_name("g1t") && !is_route_name("g1t"));
151 }
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent152}

This file's history is long; its oldest lines are credited to the oldest commit read.