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.
| The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404. | 1 | import { Users } from "lucide-react"; |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 2 | import { type ComponentProps, type KeyboardEvent, useId, useRef, useState } from "react"; |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 3 | |
| The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404. | 4 | import { type MentionMatch, mentionSuggestions } from "../lib/mention"; |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 5 | import { Textarea } from "./ui"; |
| 6 | ||
| 7 | /** | |
| The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404. | 8 | * A comment box that offers to complete the teams in `handles` |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 9 | * (`@acme/backend`): Up and Down move through the suggestions, Tab or Enter |
| 10 | * takes one, Escape dismisses them. | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 11 | */ |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 12 | export function MentionTextarea({ handles, ...props }: ComponentProps<"textarea"> & { handles?: readonly string[] }) { |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 13 | const ref = useRef<HTMLTextAreaElement>(null); |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 14 | const [match, setMatch] = useState<MentionMatch | null>(null); |
| 15 | const [active, setActive] = useState(0); | |
| 16 | const list = useId(); | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 17 | |
| 18 | const look = () => { | |
| 19 | const box = ref.current; | |
| 20 | if (!box) return; | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 21 | const found = box.selectionStart === box.selectionEnd ? mentionSuggestions(box.value, box.selectionStart, handles) : null; |
| 22 | setMatch(found); | |
| 23 | setActive(0); | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 24 | }; |
| 25 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 26 | const complete = (handle: string) => { |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 27 | const box = ref.current; |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 28 | if (!box || !match) return; |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 29 | const caret = box.selectionStart; |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 30 | box.setRangeText(`${handle} `, match.start, caret, "end"); |
| 31 | setMatch(null); | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 32 | box.focus(); |
| 33 | }; | |
| 34 | ||
| 35 | const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => { | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 36 | if (match) { |
| 37 | const count = match.options.length; | |
| 38 | if (event.key === "ArrowDown" || event.key === "ArrowUp") { | |
| 39 | event.preventDefault(); | |
| 40 | setActive((index) => (index + (event.key === "ArrowDown" ? 1 : count - 1)) % count); | |
| 41 | return; | |
| 42 | } | |
| 43 | if ((event.key === "Tab" || event.key === "Enter") && !event.shiftKey) { | |
| 44 | event.preventDefault(); | |
| 45 | complete(match.options[active] ?? match.options[0]!); | |
| 46 | return; | |
| 47 | } | |
| 48 | if (event.key === "Escape") { | |
| 49 | event.preventDefault(); | |
| 50 | setMatch(null); | |
| 51 | return; | |
| 52 | } | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 53 | } |
| 54 | props.onKeyDown?.(event); | |
| 55 | }; | |
| 56 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 57 | const open = match != null; |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 58 | return ( |
| 59 | <div className="relative"> | |
| 60 | <Textarea | |
| 61 | {...props} | |
| 62 | ref={ref} | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 63 | role={open ? "combobox" : undefined} |
| 64 | aria-autocomplete="list" | |
| 65 | aria-expanded={open} | |
| 66 | aria-controls={open ? list : undefined} | |
| 67 | aria-activedescendant={open ? `${list}-${active}` : undefined} | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 68 | onKeyDown={onKeyDown} |
| 69 | onInput={(event) => { | |
| 70 | look(); | |
| 71 | props.onInput?.(event); | |
| 72 | }} | |
| 73 | onClick={(event) => { | |
| 74 | look(); | |
| 75 | props.onClick?.(event); | |
| 76 | }} | |
| 77 | onBlur={(event) => { | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 78 | // After a click on a suggestion has landed. |
| 79 | setTimeout(() => setMatch(null), 150); | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 80 | props.onBlur?.(event); |
| 81 | }} | |
| 82 | /> | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 83 | {match && ( |
| 84 | <ul | |
| 85 | id={list} | |
| 86 | role="listbox" | |
| 87 | aria-label="Mentions" | |
| 88 | className="absolute top-full left-0 z-20 mt-1 max-w-full min-w-44 overflow-hidden rounded-md border border-line bg-raised p-1 shadow-lg shadow-black/30" | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 89 | > |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 90 | {match.options.map((handle, index) => ( |
| 91 | <li | |
| 92 | key={handle} | |
| 93 | id={`${list}-${index}`} | |
| 94 | role="option" | |
| 95 | aria-selected={index === active} | |
| 96 | onMouseDown={(event) => event.preventDefault()} | |
| 97 | onMouseEnter={() => setActive(index)} | |
| 98 | onClick={() => complete(handle)} | |
| 99 | className={`flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 font-mono text-xs text-fg ${ | |
| 100 | index === active ? "bg-line" : "" | |
| 101 | }`} | |
| 102 | > | |
| The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404. | 103 | <Users size={12} className="shrink-0 text-faint" /> |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 104 | <span className="min-w-0 truncate">{handle}</span> |
| 105 | {index === active && <span className="ml-auto pl-3 font-sans text-faint">Tab</span>} | |
| 106 | </li> | |
| 107 | ))} | |
| 108 | </ul> | |
| The docs' Copy page menu keeps its own spacing, with an icon per item | 109 | )} |
| 110 | </div> | |
| 111 | ); | |
| 112 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.