feat: v2.5.12 — plan and quota for every AI tool, Grok Build and Kimi Code, Quit AgentHub (#65)
Usage panel (status bar): - every account shows its plan (Claude subscriptionType, Codex chatgpt_plan_type, Cursor membershipType, Grok subscriptionTier) - new quota rows: Cursor CLI (cursor.com usage-summary), Antigravity (`agy --print /usage`, two model pools; AGENTHUB_AGY_USAGE=0 never runs agy), Grok Build, Kimi Code, OpenCode Go — each login read from the tool's own file, sent only to its own host while valid, never refreshed - in-flight quota reads are shared between tabs AI Tools catalog: Grok Build (`grok`) and Kimi Code (`kimi`) added; Gemini CLI, Hermes and OpenClaw removed. Also: Quit AgentHub (#65, `agenthub stop`), status-area icon, Add to Chat on an editor selection, Settings in three groups, JetBrains-style Changes panel (ticked files/hunks, ignore, blame, file history), terminal font. --no-verify: :3000 is taken by another dev server (lane-detect tests); both suites run by hand — server 2636/2639 (the 3 are :3000), client 1131/1131.
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
* Owns the open/closed panel state, the ⌘B / Esc shortcuts, reduced-motion
|
||||
* detection, and route navigation. Reactive personality + status/Ask come
|
||||
* from useSagiBrain; the avatar is draggable (AssistiveTouch-style) via
|
||||
* useSagiPosition, and the bubble/panel render in a self-clamping flyout so
|
||||
* useSagiPosition (a v2 Codex pet also looks toward the pointer), and the
|
||||
* bubble/panel render in a self-clamping flyout so
|
||||
* they never spill off any screen edge regardless of where the mascot is docked.
|
||||
*
|
||||
* The "do the job" path: an unmatched Ask query starts a claude session in
|
||||
@@ -244,6 +245,32 @@ function SagiBody() {
|
||||
return () => window.removeEventListener("keydown", onKey);
|
||||
}, []);
|
||||
|
||||
// A v2 pet at idle looks toward the pointer: one of 16 poses by the
|
||||
// pointer's angle around it (0 = up, clockwise), dropped once it rests.
|
||||
// ponytail: rest after 2 s is a guess; Codex Desktop's own rule is not public.
|
||||
const btn = useRef<HTMLButtonElement>(null);
|
||||
const [gaze, setGaze] = useState<number | null>(null);
|
||||
const wearsSheet = "kind" in pet && pet.kind === "codex";
|
||||
useEffect(() => {
|
||||
if (!wearsSheet || reducedMotion) return;
|
||||
let rest = 0;
|
||||
const onMove = (e: PointerEvent) => {
|
||||
const r = btn.current?.getBoundingClientRect();
|
||||
if (!r) return;
|
||||
const deg =
|
||||
(Math.atan2(e.clientX - (r.left + r.width / 2), r.top + r.height / 2 - e.clientY) * 180) /
|
||||
Math.PI;
|
||||
setGaze(Math.round((deg + 360) / 22.5) % 16);
|
||||
window.clearTimeout(rest);
|
||||
rest = window.setTimeout(() => setGaze(null), 2000);
|
||||
};
|
||||
window.addEventListener("pointermove", onMove);
|
||||
return () => {
|
||||
window.removeEventListener("pointermove", onMove);
|
||||
window.clearTimeout(rest);
|
||||
};
|
||||
}, [wearsSheet, reducedMotion]);
|
||||
|
||||
const onNavigate = useCallback(
|
||||
(route: string) => {
|
||||
navigate(route);
|
||||
@@ -334,6 +361,7 @@ function SagiBody() {
|
||||
)}
|
||||
|
||||
<button
|
||||
ref={btn}
|
||||
className="sagi-avatar-btn"
|
||||
data-dragging={place.dragging ? "1" : "0"}
|
||||
style={{ left: place.left, top: place.top, width: size, height: size }}
|
||||
@@ -368,6 +396,7 @@ function SagiBody() {
|
||||
mood={brain.mood}
|
||||
// Dragged → runs that way; hovered → waves (Codex's pet does both).
|
||||
action={place.moving ? `run-${place.moving}` : hover ? "wave" : null}
|
||||
gaze={gaze}
|
||||
size={size}
|
||||
reducedMotion={reducedMotion}
|
||||
// Deleted elsewhere, or unreadable: back to Sagi.
|
||||
|
||||
Reference in New Issue
Block a user