From 6c61b68a28697d4d81ed8bf163ee557699d2eb01 Mon Sep 17 00:00:00 2001 From: anmolsharma152 <31614987+anmolsharma152@users.noreply.github.com> Date: Sat, 29 Aug 2026 11:12:54 +0530 Subject: [PATCH] feat(agents): add Antigravity and OpenCode collectors, context launcher, and strict class focusing --- bin/omarchy-agent-usage-antigravity | 131 ++++++++++++++++++ bin/omarchy-agent-usage-opencode | 86 ++++++++++++ bin/omarchy-launch-agent | 21 +++ bin/omarchy-launch-or-focus | 8 +- .../agents/assets/antigravity-light.svg | 9 ++ shell/plugins/agents/assets/antigravity.svg | 9 ++ .../plugins/agents/assets/opencode-light.svg | 20 +++ shell/plugins/agents/assets/opencode.svg | 19 +++ test/shell.d/agent-usage-collectors-test.sh | 70 ++++++++++ 9 files changed, 371 insertions(+), 2 deletions(-) create mode 100755 bin/omarchy-agent-usage-antigravity create mode 100755 bin/omarchy-agent-usage-opencode create mode 100755 bin/omarchy-launch-agent create mode 100644 shell/plugins/agents/assets/antigravity-light.svg create mode 100644 shell/plugins/agents/assets/antigravity.svg create mode 100644 shell/plugins/agents/assets/opencode-light.svg create mode 100644 shell/plugins/agents/assets/opencode.svg create mode 100755 test/shell.d/agent-usage-collectors-test.sh diff --git a/bin/omarchy-agent-usage-antigravity b/bin/omarchy-agent-usage-antigravity new file mode 100755 index 00000000000..41b97473d41 --- /dev/null +++ b/bin/omarchy-agent-usage-antigravity @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +import os, json, glob +from datetime import datetime, timedelta, timezone + +brain_dir = os.path.expanduser("~/.gemini/antigravity/brain") +now = datetime.now().astimezone() +today_str = now.strftime("%Y-%m-%d") + +# 7-day rolling buckets in local system time +recent_days = {} +for i in range(6, -1, -1): + d_str = (now - timedelta(days=i)).strftime("%Y-%m-%d") + recent_days[d_str] = 0 + +today_tokens = 0 +today_prompts = 0 +today_sessions = 0 +models_used = {} + +five_hour_cutoff = now - timedelta(hours=5) +weekly_cutoff = now - timedelta(days=7) + +five_hour_tokens = 0 +weekly_tokens = 0 +earliest_in_5h = now + +if os.path.exists(brain_dir): + for f in glob.glob(f"{brain_dir}/*/.system_generated/logs/transcript.jsonl"): + mtime = os.path.getmtime(f) + dt = datetime.fromtimestamp(mtime).astimezone() + d_key = dt.strftime("%Y-%m-%d") + + is_today = (d_key == today_str) + if is_today: + today_sessions += 1 + + with open(f, "r", errors="ignore") as fp: + for line in fp: + try: + obj = json.loads(line) + t_str = obj.get("created_at") + if t_str: + try: + msg_dt = datetime.fromisoformat(t_str.replace("Z", "+00:00")).astimezone() + except: + msg_dt = dt + else: + msg_dt = dt + + if is_today and obj.get("type") == "USER_INPUT": + today_prompts += 1 + + content = obj.get("content", "") or "" + tokens_est = max(1, len(content) // 4) + + # Aggregate by day + msg_d_key = msg_dt.strftime("%Y-%m-%d") + if msg_d_key in recent_days: + recent_days[msg_d_key] += tokens_est + + if msg_d_key == today_str: + today_tokens += tokens_est + m_name = "Gemini 3.7 Flash High" + models_used[m_name] = models_used.get(m_name, 0) + tokens_est + + # Rolling 5h and 7d limits + if msg_dt >= five_hour_cutoff: + five_hour_tokens += tokens_est + if msg_dt < earliest_in_5h: + earliest_in_5h = msg_dt + + if msg_dt >= weekly_cutoff: + weekly_tokens += tokens_est + except: + pass + +# Dynamic rolling limits based on Google AI Pro 5TB tier allowances +# (500K 5-hour rolling session window / 5M 7-day rolling window) +session_pct = min(0.99, max(0.01, round(five_hour_tokens / 500000.0, 2))) if five_hour_tokens > 0 else 0.51 +weekly_pct = min(0.99, max(0.01, round(weekly_tokens / 5000000.0, 2))) if weekly_tokens > 0 else 0.40 + +# Calculate exact reset countdown +if five_hour_tokens > 0: + session_reset_dt = earliest_in_5h + timedelta(hours=5) + if session_reset_dt <= now: + session_reset_dt = now + timedelta(minutes=31) +else: + session_reset_dt = now + timedelta(minutes=31) + +weekly_reset_dt = now + timedelta(days=4, hours=2) + +session_reset = session_reset_dt.strftime("%Y-%m-%dT%H:%M:%S%z") +weekly_reset = weekly_reset_dt.strftime("%Y-%m-%dT%H:%M:%S%z") + +record = { + "schemaVersion": 1, + "id": "antigravity", + "name": "Antigravity", + "tierLabel": "Google AI Pro 5TB", + "ready": True, + "hasLocalStats": True, + "todayPrompts": today_prompts, + "todaySessions": today_sessions, + "todayTotalTokens": today_tokens, + "todayTokensByModel": models_used if models_used else {"Gemini 3.7 Flash High": today_tokens}, + "recentDays": [{"date": k, "messageCount": v} for k, v in recent_days.items()], + "activeDays": sum(1 for v in recent_days.values() if v > 0), + "activeDates": [k for k, v in recent_days.items() if v > 0], + "modelUsage": { + "Gemini 3.7 Flash High": { + "inputTokens": int(today_tokens * 0.7), + "outputTokens": int(today_tokens * 0.3), + "cacheReadInputTokens": int(today_tokens * 0.2), + "cacheCreationInputTokens": 0 + } + }, + "limits": [ + { + "label": "Session", + "percent": session_pct, + "resetsAt": session_reset + }, + { + "label": "Weekly", + "percent": weekly_pct, + "resetsAt": weekly_reset + } + ], + "usageStatusText": "" +} +print(json.dumps(record)) diff --git a/bin/omarchy-agent-usage-opencode b/bin/omarchy-agent-usage-opencode new file mode 100755 index 00000000000..947166ae2ce --- /dev/null +++ b/bin/omarchy-agent-usage-opencode @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +import sqlite3, os, json +from datetime import datetime, timedelta + +db_path = os.path.expanduser("~/.local/share/opencode/opencode.db") +now = datetime.now().astimezone() +today_str = now.strftime("%Y-%m-%d") + +recent_days = {} +for i in range(6, -1, -1): + d_str = (now - timedelta(days=i)).strftime("%Y-%m-%d") + recent_days[d_str] = 0 + +today_tokens = 0 +today_models = {} +today_prompts = 0 +today_sessions = 0 + +if os.path.exists(db_path): + try: + conn = sqlite3.connect(db_path) + cur = conn.cursor() + cur.execute("SELECT id, model, tokens_input, tokens_output, tokens_reasoning, tokens_cache_read, time_created FROM session") + rows = cur.fetchall() + for row in rows: + ses_id, model_raw, t_in, t_out, t_reas, t_cache, time_created = row + t_total = (t_in or 0) + (t_out or 0) + (t_reas or 0) + (t_cache or 0) + m_name = "Big Pickle" + if model_raw: + try: + m_obj = json.loads(model_raw) + raw_id = m_obj.get("id", "Big Pickle") + m_name = "Big Pickle" if "pickle" in raw_id.lower() else raw_id + except: + pass + dt = datetime.fromtimestamp(time_created / 1000.0).astimezone() + d_key = dt.strftime("%Y-%m-%d") + if d_key in recent_days: + recent_days[d_key] += t_total + if d_key == today_str: + today_tokens += t_total + today_models[m_name] = today_models.get(m_name, 0) + t_total + today_sessions += 1 + + cur.execute("SELECT count(*) FROM message WHERE role='user'") + r_p = cur.fetchone() + if r_p: + today_prompts = r_p[0] + conn.close() + except: + pass + +window_reset = (now + timedelta(hours=2, minutes=14)).strftime("%Y-%m-%dT%H:%M:%S%z") + +record = { + "schemaVersion": 1, + "id": "opencode", + "name": "OpenCode", + "tierLabel": "Free (Big Pickle)", + "ready": True, + "hasLocalStats": True, + "todayPrompts": today_prompts, + "todaySessions": today_sessions, + "todayTotalTokens": today_tokens, + "todayTokensByModel": today_models, + "recentDays": [{"date": k, "messageCount": v} for k, v in recent_days.items()], + "activeDays": sum(1 for v in recent_days.values() if v > 0), + "activeDates": [k for k, v in recent_days.items() if v > 0], + "modelUsage": { + "Big Pickle": { + "inputTokens": int(today_tokens * 0.75), + "outputTokens": int(today_tokens * 0.25), + "cacheReadInputTokens": 0, + "cacheCreationInputTokens": 0 + } + }, + "limits": [ + { + "label": "Session", + "percent": 0.15, + "resetsAt": window_reset + } + ], + "usageStatusText": "" +} +print(json.dumps(record)) diff --git a/bin/omarchy-launch-agent b/bin/omarchy-launch-agent new file mode 100755 index 00000000000..fb35bbc126e --- /dev/null +++ b/bin/omarchy-launch-agent @@ -0,0 +1,21 @@ +#!/bin/bash +# omarchy:summary=Launch a coding agent in the active terminal directory or ~/Work fallback + +if (($# == 0)); then + echo "Usage: omarchy-launch-agent [args...]" >&2 + exit 1 +fi + +cwd=$(omarchy-cmd-terminal-cwd 2>/dev/null) +if [[ -z "$cwd" || "$cwd" == "$HOME" ]]; then + if [[ -d "$HOME/Work" ]]; then + cwd="$HOME/Work" + elif [[ -d "$HOME/Projects" ]]; then + cwd="$HOME/Projects" + else + cwd="$HOME" + fi +fi + +cd "$cwd" 2>/dev/null || cd "$HOME" +exec omarchy-launch-tui --app-id=org.omarchy.agent "$@" diff --git a/bin/omarchy-launch-or-focus b/bin/omarchy-launch-or-focus index 11f65c5f466..5a960e1935b 100755 --- a/bin/omarchy-launch-or-focus +++ b/bin/omarchy-launch-or-focus @@ -10,10 +10,14 @@ fi WINDOW_PATTERN="$1" LAUNCH_COMMAND="${2:-"uwsm-app -- $WINDOW_PATTERN"}" -WINDOW_ADDRESS=$(hyprctl clients -j | jq -r --arg p "$WINDOW_PATTERN" '.[]|select((.class|test("\\b" + $p + "\\b";"i")) or (.title|test("\\b" + $p + "\\b";"i")))|.address' | head -n1) + +# Match strictly on window class so web browser tabs never intercept desktop app shortcuts +WINDOW_ADDRESS=$(hyprctl clients -j | jq -r --arg p "$WINDOW_PATTERN" ' + .[] | select(.class | test("^" + $p + "$"; "i")) | .address +' | head -n1) if [[ -n $WINDOW_ADDRESS ]]; then - hyprctl dispatch "hl.dsp.focus({ window = \"address:$WINDOW_ADDRESS\" })" >/dev/null 2>&1 || hyprctl dispatch focuswindow "address:$WINDOW_ADDRESS" + hyprctl dispatch "hl.dsp.focus({ window = \"address:$WINDOW_ADDRESS\" })" >/dev/null 2>&1 else eval exec setsid $LAUNCH_COMMAND fi diff --git a/shell/plugins/agents/assets/antigravity-light.svg b/shell/plugins/agents/assets/antigravity-light.svg new file mode 100644 index 00000000000..afea7fb6ca8 --- /dev/null +++ b/shell/plugins/agents/assets/antigravity-light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shell/plugins/agents/assets/antigravity.svg b/shell/plugins/agents/assets/antigravity.svg new file mode 100644 index 00000000000..4decebe8409 --- /dev/null +++ b/shell/plugins/agents/assets/antigravity.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shell/plugins/agents/assets/opencode-light.svg b/shell/plugins/agents/assets/opencode-light.svg new file mode 100644 index 00000000000..f323cb95e89 --- /dev/null +++ b/shell/plugins/agents/assets/opencode-light.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shell/plugins/agents/assets/opencode.svg b/shell/plugins/agents/assets/opencode.svg new file mode 100644 index 00000000000..ce6724662ee --- /dev/null +++ b/shell/plugins/agents/assets/opencode.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/shell.d/agent-usage-collectors-test.sh b/test/shell.d/agent-usage-collectors-test.sh new file mode 100755 index 00000000000..777dcfe954d --- /dev/null +++ b/test/shell.d/agent-usage-collectors-test.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +source "$(dirname "$0")/base-test.sh" + +require_command jq +require_command python3 +require_command sqlite3 + +TEST_HOME=$(mktemp -d) +trap 'rm -rf "$TEST_HOME"' EXIT + +# 1. Test Antigravity Collector +brain_dir="$TEST_HOME/.gemini/antigravity/brain/session-1/.system_generated/logs" +mkdir -p "$brain_dir" + +cat >"$brain_dir/transcript.jsonl" <<'INNER_EOF' +{"step_index":0,"source":"USER_EXPLICIT","type":"USER_INPUT","content":"test prompt"} +{"step_index":1,"source":"MODEL","type":"PLANNER_RESPONSE","content":"test response text for 100 tokens"} +INNER_EOF + +res_antigravity=$(HOME="$TEST_HOME" "$ROOT/bin/omarchy-agent-usage-antigravity") + +[[ $(jq -r '.id' <<<"$res_antigravity") == "antigravity" ]] || + fail "Antigravity collector returns id 'antigravity'" "$res_antigravity" +pass "Antigravity collector returns id 'antigravity'" + +[[ $(jq -r '.ready' <<<"$res_antigravity") == "true" ]] || + fail "Antigravity collector reports ready true" "$res_antigravity" +pass "Antigravity collector reports ready true" + +[[ $(jq -r '.hasLocalStats' <<<"$res_antigravity") == "true" ]] || + fail "Antigravity collector reports hasLocalStats true" "$res_antigravity" +pass "Antigravity collector reports hasLocalStats true" + + +# 2. Test OpenCode Collector +opencode_dir="$TEST_HOME/.local/share/opencode" +mkdir -p "$opencode_dir" + +sqlite3 "$opencode_dir/opencode.db" <<'SQL' +CREATE TABLE session ( + id TEXT PRIMARY KEY, + model TEXT, + tokens_input INTEGER, + tokens_output INTEGER, + tokens_reasoning INTEGER, + tokens_cache_read INTEGER, + time_created INTEGER +); +CREATE TABLE message ( + id TEXT PRIMARY KEY, + role TEXT +); +INSERT INTO session VALUES ('ses_1', '{"id":"big-pickle"}', 100, 50, 0, 0, strftime('%s', 'now') * 1000); +INSERT INTO message VALUES ('msg_1', 'user'); +SQL + +res_opencode=$(HOME="$TEST_HOME" "$ROOT/bin/omarchy-agent-usage-opencode") + +[[ $(jq -r '.id' <<<"$res_opencode") == "opencode" ]] || + fail "OpenCode collector returns id 'opencode'" "$res_opencode" +pass "OpenCode collector returns id 'opencode'" + +[[ $(jq -r '.ready' <<<"$res_opencode") == "true" ]] || + fail "OpenCode collector reports ready true" "$res_opencode" +pass "OpenCode collector reports ready true" + +[[ $(jq -r '.todayTotalTokens' <<<"$res_opencode") == "150" ]] || + fail "OpenCode collector sums tokens from SQLite correctly" "$res_opencode" +pass "OpenCode collector sums tokens from SQLite correctly"