Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions bin/omarchy-agent-usage-antigravity
Original file line number Diff line number Diff line change
@@ -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))
86 changes: 86 additions & 0 deletions bin/omarchy-agent-usage-opencode
Original file line number Diff line number Diff line change
@@ -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))
21 changes: 21 additions & 0 deletions bin/omarchy-launch-agent
Original file line number Diff line number Diff line change
@@ -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 <command> [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 "$@"
8 changes: 6 additions & 2 deletions bin/omarchy-launch-or-focus
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions shell/plugins/agents/assets/antigravity-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions shell/plugins/agents/assets/antigravity.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions shell/plugins/agents/assets/opencode-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions shell/plugins/agents/assets/opencode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions test/shell.d/agent-usage-collectors-test.sh
Original file line number Diff line number Diff line change
@@ -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"